diff --git a/NODE_TYPES b/NODE_TYPES deleted file mode 100644 index 1284ea7db0..0000000000 --- a/NODE_TYPES +++ /dev/null @@ -1,94 +0,0 @@ -- name: Assignment - child_nodes: - - node target - - token operator - - node value - location: target->value -- name: Binary - child_nodes: - - node left - - token operator - - node right - location: left->right -- name: CharacterLiteral - child_nodes: - - token value - location: value -- name: FloatLiteral - child_nodes: - - token value - location: value -- name: Identifier - child_nodes: - - token value - location: value -- name: IfModifier - child_nodes: - - node statement - - token keyword - - node predicate - location: statement->predicate -- name: ImaginaryLiteral - child_nodes: - - token value - location: value -- name: IntegerLiteral - child_nodes: - - token value - location: value -- name: OperatorAssignment - child_nodes: - - node target - - token operator - - node value - location: target->value -- name: Program - child_nodes: - - node statements - location: statements -- name: RationalLiteral - child_nodes: - - token value - location: value -- name: Redo - child_nodes: - - token value - location: value -- name: Retry - child_nodes: - - token value - location: value -- name: Statements - child_nodes: - - node[] body - location: body -- name: Ternary - child_nodes: - - node predicate - - token question_mark - - node true_expression - - token colon - - node false_expression - location: predicate->false_expression -- name: UnlessModifier - child_nodes: - - node statement - - token keyword - - node predicate - location: statement->predicate -- name: UntilModifier - child_nodes: - - node statement - - token keyword - - node predicate - location: statement->predicate -- name: VariableReference - child_nodes: - - token value - location: value -- name: WhileModifier - child_nodes: - - node statement - - token keyword - - node predicate - location: statement->predicate diff --git a/TOKEN_TYPES b/TOKEN_TYPES deleted file mode 100644 index c81d8f60ac..0000000000 --- a/TOKEN_TYPES +++ /dev/null @@ -1,275 +0,0 @@ -- name: EOF - value: 0 - comment: final token in the file -- name: INVALID - comment: "an invalid token" -- name: AMPERSAND - comment: "&" -- name: AMPERSAND_AMPERSAND - comment: "&&" -- name: AMPERSAND_AMPERSAND_EQUAL - comment: "&&=" -- name: AMPERSAND_EQUAL - comment: "&=" -- name: BACK_REFERENCE - comment: "a back reference" -- name: BACKTICK - comment: "`" -- name: BANG - comment: "!" -- name: BANG_AT - comment: "!@" -- name: BANG_EQUAL - comment: "!=" -- name: BANG_TILDE - comment: "!~" -- name: BRACE_LEFT - comment: "{" -- name: BRACE_RIGHT - comment: "}" -- name: BRACKET_LEFT - comment: "[" -- name: BRACKET_LEFT_RIGHT - comment: "[]" -- name: BRACKET_RIGHT - comment: "]" -- name: CARET - comment: "^" -- name: CARET_EQUAL - comment: "^=" -- name: CHARACTER_LITERAL - comment: "a character literal" -- name: CLASS_VARIABLE - comment: "a class variable" -- name: COLON - comment: ":" -- name: COLON_COLON - comment: "::" -- name: COMMA - comment: "," -- name: COMMENT - comment: "a comment" -- name: CONSTANT - comment: "a constant" -- name: DOT - comment: "." -- name: DOT_DOT - comment: ".." -- name: DOT_DOT_DOT - comment: "..." -- name: EMBDOC_BEGIN - comment: "=begin" -- name: EMBDOC_END - comment: "=end" -- name: EMBDOC_LINE - comment: "a line inside of embedded documentation" -- name: EMBEXPR_BEGIN - comment: "#{" -- name: EMBEXPR_END - comment: "}" -- name: EQUAL - comment: "=" -- name: EQUAL_EQUAL - comment: "==" -- name: EQUAL_EQUAL_EQUAL - comment: "===" -- name: EQUAL_GREATER - comment: "=>" -- name: EQUAL_TILDE - comment: "=~" -- name: FLOAT - comment: "a floating point number" -- name: GREATER - comment: ">" -- name: GREATER_EQUAL - comment: ">=" -- name: GREATER_GREATER - comment: ">>" -- name: GREATER_GREATER_EQUAL - comment: ">>=" -- name: GLOBAL_VARIABLE - comment: "a global variable" -- name: IDENTIFIER - comment: "an identifier" -- name: IMAGINARY_NUMBER - comment: "an imaginary number literal" -- name: INSTANCE_VARIABLE - comment: "an instance variable" -- name: INTEGER - comment: "an integer (any base)" -- name: KEYWORD___ENCODING__ - comment: "__ENCODING__" -- name: KEYWORD___LINE__ - comment: "__LINE__" -- name: KEYWORD___FILE__ - comment: "__FILE__" -- name: KEYWORD_ALIAS - comment: "alias" -- name: KEYWORD_AND - comment: "and" -- name: KEYWORD_BEGIN - comment: "begin" -- name: KEYWORD_BEGIN_UPCASE - comment: "BEGIN" -- name: KEYWORD_BREAK - comment: "break" -- name: KEYWORD_CASE - comment: "case" -- name: KEYWORD_CLASS - comment: "class" -- name: KEYWORD_DEF - comment: "def" -- name: KEYWORD_DEFINED - comment: "defined?" -- name: KEYWORD_DO - comment: "do" -- name: KEYWORD_ELSE - comment: "else" -- name: KEYWORD_ELSIF - comment: "elsif" -- name: KEYWORD_END - comment: "end" -- name: KEYWORD_END_UPCASE - comment: "END" -- name: KEYWORD_ENSURE - comment: "ensure" -- name: KEYWORD_FALSE - comment: "false" -- name: KEYWORD_FOR - comment: "for" -- name: KEYWORD_IF - comment: "if" -- name: KEYWORD_IN - comment: "in" -- name: KEYWORD_MODULE - comment: "module" -- name: KEYWORD_NEXT - comment: "next" -- name: KEYWORD_NIL - comment: "nil" -- name: KEYWORD_NOT - comment: "not" -- name: KEYWORD_OR - comment: "or" -- name: KEYWORD_REDO - comment: "redo" -- name: KEYWORD_RESCUE - comment: "rescue" -- name: KEYWORD_RETRY - comment: "retry" -- name: KEYWORD_RETURN - comment: "return" -- name: KEYWORD_SELF - comment: "self" -- name: KEYWORD_SUPER - comment: "super" -- name: KEYWORD_THEN - comment: "then" -- name: KEYWORD_TRUE - comment: "true" -- name: KEYWORD_UNDEF - comment: "undef" -- name: KEYWORD_UNLESS - comment: "unless" -- name: KEYWORD_UNTIL - comment: "until" -- name: KEYWORD_WHEN - comment: "when" -- name: KEYWORD_WHILE - comment: "while" -- name: KEYWORD_YIELD - comment: "yield" -- name: LABEL - comment: "a label" -- name: LAMBDA_BEGIN - comment: "{" -- name: LESS - comment: "<" -- name: LESS_EQUAL - comment: "<=" -- name: LESS_EQUAL_GREATER - comment: "<=>" -- name: LESS_LESS - comment: "<<" -- name: LESS_LESS_EQUAL - comment: "<<=" -- name: MINUS - comment: "-" -- name: MINUS_AT - comment: "-@" -- name: MINUS_EQUAL - comment: "-=" -- name: MINUS_GREATER - comment: "->" -- name: NEWLINE - comment: "a newline character outside of other tokens" -- name: NTH_REFERENCE - comment: "an nth global variable reference" -- name: PARENTHESIS_LEFT - comment: "(" -- name: PARENTHESIS_RIGHT - comment: ")" -- name: PERCENT - comment: "%" -- name: PERCENT_EQUAL - comment: "%=" -- name: PERCENT_LOWER_I - comment: "%i" -- name: PERCENT_LOWER_W - comment: "%w" -- name: PERCENT_LOWER_X - comment: "%x" -- name: PERCENT_UPPER_I - comment: "%I" -- name: PERCENT_UPPER_W - comment: "%W" -- name: PIPE - comment: "|" -- name: PIPE_EQUAL - comment: "|=" -- name: PIPE_PIPE - comment: "||" -- name: PIPE_PIPE_EQUAL - comment: "||=" -- name: PLUS - comment: "+" -- name: PLUS_AT - comment: "+@" -- name: PLUS_EQUAL - comment: "+=" -- name: QUESTION_MARK - comment: "?" -- name: RATIONAL_NUMBER - comment: "a rational number literal" -- name: REGEXP_BEGIN - comment: "the beginning of a regular expression" -- name: REGEXP_END - comment: "the end of a regular expression" -- name: SEMICOLON - comment: ";" -- name: SLASH - comment: "/" -- name: SLASH_EQUAL - comment: "/=" -- name: STAR - comment: "*" -- name: STAR_EQUAL - comment: "*=" -- name: STAR_STAR - comment: "**" -- name: STAR_STAR_EQUAL - comment: "**=" -- name: STRING_BEGIN - comment: "the beginning of a string" -- name: STRING_CONTENT - comment: "the contents of a string" -- name: STRING_END - comment: "the end of a string" -- name: SYMBOL_BEGIN - comment: "the beginning of a symbol" -- name: TILDE - comment: "~" -- name: TILDE_AT - comment: "~@" -- name: WORDS_SEP - comment: "a separator between words in a list" diff --git a/bin/template b/bin/template index 20e10b0c8e..290c872a08 100755 --- a/bin/template +++ b/bin/template @@ -145,9 +145,9 @@ end ROOT_DIR = File.expand_path('..', __dir__) -def template(name, types, mark) +def template(name, nodes, mark) filepath = File.expand_path(name, __dir__) - contents = File.read(filepath).gsub(mark, ERB.new(File.read(File.expand_path("templates/#{File.basename(name)}.erb", __dir__)), trim_mode: "-").result_with_hash(types: types)) + contents = File.read(filepath).gsub(mark, ERB.new(File.read(File.expand_path("templates/#{File.basename(name)}.erb", __dir__)), trim_mode: "-").result_with_hash(nodes: nodes)) File.write(filepath, contents) if ['.c', '.h'].include?(File.extname(filepath)) @@ -187,18 +187,15 @@ RBMARKBEGIN ############################################################################## RBMARKEND -types = [] -YAML.load_file(File.expand_path("../NODE_TYPES", __dir__)).each do |config| - types << NodeType.new(config) -end -types.sort_by!(&:name) +config = YAML.load_file(File.expand_path("../config.yml", __dir__)) -tokens = YAML.load_file(File.join(ROOT_DIR, 'TOKEN_TYPES')).map { |config| Token.new(config) } +nodes = config.fetch("nodes").map { |node| NodeType.new(node) }.sort_by(&:name) +tokens = config.fetch("tokens").map { |token| Token.new(token) } -template("../ext/yarp/extension.c", types, cmark) -template("../ext/yarp/yarp.h", types, cmark) -template("../ext/yarp/yarp.c", types, cmark) -template("../lib/yarp.rb", types, rbmark) +template("../ext/yarp/extension.c", nodes, cmark) +template("../ext/yarp/yarp.h", nodes, cmark) +template("../ext/yarp/yarp.c", nodes, cmark) +template("../lib/yarp.rb", nodes, rbmark) pure_template(template: 'bin/templates/token_type.h.erb', write_to: 'ext/yarp/token_type.h', locals: { tokens: tokens }) pure_template(template: 'bin/templates/token_type.c.erb', write_to: 'ext/yarp/token_type.c', locals: { tokens: tokens }) diff --git a/bin/templates/extension.c.erb b/bin/templates/extension.c.erb index 18fb1665d8..c3dda5ff9f 100644 --- a/bin/templates/extension.c.erb +++ b/bin/templates/extension.c.erb @@ -5,29 +5,29 @@ static VALUE node_new(yp_parser_t *parser, yp_node_t *node) { switch (node->type) { - <%- types.each do |type| -%> - case <%= type.type %>: { - VALUE argv[<%= type.params.length + 1 %>]; - <%- type.params.each_with_index do |param, index| -%> + <%- nodes.each do |node| -%> + case <%= node.type %>: { + VALUE argv[<%= node.params.length + 1 %>]; + <%- node.params.each_with_index do |param, index| -%> // <%= param.name %> <%- case param -%> <%- when NodeParam -%> - argv[<%= index %>] = node_new(parser, node->as.<%= type.human %>.<%= param.name %>); + argv[<%= index %>] = node_new(parser, node->as.<%= node.human %>.<%= param.name %>); <%- when NodeListParam -%> argv[<%= index %>] = rb_ary_new(); - for (size_t index = 0; index < node->as.<%= type.human %>.<%= param.name %>->size; index++) { - rb_ary_push(argv[<%= index %>], node_new(parser, node->as.<%= type.human %>.<%= param.name %>->nodes[index])); + for (size_t index = 0; index < node->as.<%= node.human %>.<%= param.name %>->size; index++) { + rb_ary_push(argv[<%= index %>], node_new(parser, node->as.<%= node.human %>.<%= param.name %>->nodes[index])); } <%- when TokenParam -%> - argv[<%= index %>] = token_new(parser, &node->as.<%= type.human %>.<%= param.name %>); + argv[<%= index %>] = token_new(parser, &node->as.<%= node.human %>.<%= param.name %>); <%- end -%> <%- end -%> // location - argv[<%= type.params.length %>] = location_new(&node->location); + argv[<%= node.params.length %>] = location_new(&node->location); - return rb_class_new_instance(<%= type.params.length + 1 %>, argv, rb_const_get_at(rb_cYARP, rb_intern("<%= type.name %>"))); + return rb_class_new_instance(<%= node.params.length + 1 %>, argv, rb_const_get_at(rb_cYARP, rb_intern("<%= node.name %>"))); } <%- end -%> default: diff --git a/bin/templates/yarp.c.erb b/bin/templates/yarp.c.erb index 7f8b518f41..e89adc559f 100644 --- a/bin/templates/yarp.c.erb +++ b/bin/templates/yarp.c.erb @@ -2,17 +2,17 @@ /* BEGIN TEMPLATE */ /******************************************************************************/ -<%- types.each do |type| -%> -// Allocate a new <%= type.name %> node. +<%- nodes.each do |node| -%> +// Allocate a new <%= node.name %> node. static yp_node_t * -<%- params = type.params.map(&:param).compact.join(", ") -%> -yp_node_alloc_<%= type.human %>(yp_parser_t *parser<%= params.empty? ? "" : ", #{params}" %>) { +<%- params = node.params.map(&:param).compact.join(", ") -%> +yp_node_alloc_<%= node.human %>(yp_parser_t *parser<%= params.empty? ? "" : ", #{params}" %>) { yp_node_t *node = yp_node_alloc(parser); *node = (yp_node_t) { - .type = <%= type.type %>, - .location = <%= type.location.to_c %>, - .as.<%= type.human %> = { - <%- type.params.each do |param| -%> + .type = <%= node.type %>, + .location = <%= node.location.to_c %>, + .as.<%= node.human %> = { + <%- node.params.each do |param| -%> .<%= param.name %> = <%= param.assign %>, <%- end -%> }, @@ -27,14 +27,14 @@ yp_node_alloc_<%= type.human %>(yp_parser_t *parser<%= params.empty? ? "" : ", # void yp_node_dealloc(yp_parser_t *parser, yp_node_t *node) { switch (node->type) { - <%- types.each do |type| -%> - case <%= type.type %>: - <%- type.params.each do |param| -%> + <%- nodes.each do |node| -%> + case <%= node.type %>: + <%- node.params.each do |param| -%> <%- case param -%> <%- when NodeParam -%> - yp_node_dealloc(parser, node->as.<%= type.human %>.<%= param.name %>); + yp_node_dealloc(parser, node->as.<%= node.human %>.<%= param.name %>); <%- when NodeListParam -%> - yp_node_list_dealloc(parser, node->as.<%= type.human %>.<%= param.name %>); + yp_node_list_dealloc(parser, node->as.<%= node.human %>.<%= param.name %>); <%- end -%> <%- end -%> free(node); diff --git a/bin/templates/yarp.h.erb b/bin/templates/yarp.h.erb index 54384306d6..e513204362 100644 --- a/bin/templates/yarp.h.erb +++ b/bin/templates/yarp.h.erb @@ -3,8 +3,8 @@ /******************************************************************************/ typedef enum { -<%- types.each do |type| -%> - <%= type.type %>, +<%- nodes.each do |node| -%> + <%= node.type %>, <%- end -%> } yp_node_type_t; @@ -24,14 +24,14 @@ typedef struct yp_node { // optimization here by combining node types that share the same shape, but // it might not end up mattering in the final compiled code. union { - <%- types.each do |type| -%> - // <%= type.name %> + <%- nodes.each do |node| -%> + // <%= node.name %> struct { - <%- type.params.each do |param| -%> + <%- node.params.each do |param| -%> <%= param.decl %>; <%- end -%> - } <%= type.human %>; -<%= "\n" if type != types.last -%> + } <%= node.human %>; +<%= "\n" if node != nodes.last -%> <%- end -%> } as; } yp_node_t; diff --git a/bin/templates/yarp.rb.erb b/bin/templates/yarp.rb.erb index 40cf91165b..f7415ca440 100644 --- a/bin/templates/yarp.rb.erb +++ b/bin/templates/yarp.rb.erb @@ -2,19 +2,19 @@ # BEGIN TEMPLATE # ############################################################################## - <%- types.each do |type| -%> - class <%= type.name -%> < Node - <%- type.params.each do |type| -%> - # attr_reader <%= type.name %>: <%= type.rbs_class %> - attr_reader :<%= type.name %> + <%- nodes.each do |node| -%> + class <%= node.name -%> < Node + <%- node.params.each do |param| -%> + # attr_reader <%= param.name %>: <%= param.rbs_class %> + attr_reader :<%= param.name %> <%- end -%> # attr_reader location: Location attr_reader :location - # def initialize: (<%= type.params.map { |param| "#{param.name}: #{param.rbs_class}" }.join(", ") %>, location: Location) -> void - def initialize(<%= type.params.map(&:name).join(", ") %>, location) - <%- type.params.each do |param| -%> + # def initialize: (<%= node.params.map { |param| "#{param.name}: #{param.rbs_class}" }.join(", ") %>, location: Location) -> void + def initialize(<%= node.params.map(&:name).join(", ") %>, location) + <%- node.params.each do |param| -%> @<%= param.name %> = <%= param.name %> <%- end -%> @location = location @@ -22,12 +22,12 @@ # def accept: (visitor: Visitor) -> void def accept(visitor) - visitor.visit_<%= type.human %>(self) + visitor.visit_<%= node.human %>(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes - [<%= type.params.map(&:child_nodes).compact.join(", ") %>] + [<%= node.params.map(&:child_nodes).compact.join(", ") %>] end # def deconstruct: () -> Array[nil | Node] @@ -35,30 +35,30 @@ # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Token | Node | Array[Node] | Location] def deconstruct_keys(keys) - { <%= type.params.map { |param| "#{param.name}: #{param.name}" }.join(", ") %>, location: location } + { <%= node.params.map { |param| "#{param.name}: #{param.name}" }.join(", ") %>, location: location } end # def ==(other: Object) -> bool def ==(other) - other in <%= type.name %>[<%= type.params.map { |param| "#{param.name}: ^(#{param.name})" }.join(", ") %>] + other in <%= node.name %>[<%= node.params.map { |param| "#{param.name}: ^(#{param.name})" }.join(", ") %>] end end <%- end -%> class Visitor < BasicVisitor - <%- types.each do |type| -%> - # Visit a <%= type.name %> node - alias visit_<%= type.human %> visit_child_nodes -<%= "\n" if type != types.last -%> + <%- nodes.each do |node| -%> + # Visit a <%= node.name %> node + alias visit_<%= node.human %> visit_child_nodes +<%= "\n" if node != nodes.last -%> <%- end -%> end module DSL private - <%- types.each do |type| -%> + <%- nodes.each do |node| -%> - # Create a new <%= type.name %> node - def <%= type.name %>(<%= type.params.map(&:name).join(", ") %>) = <%= type.name %>.new(<%= type.params.map(&:name).join(", ") %>, Location.null) + # Create a new <%= node.name %> node + def <%= node.name %>(<%= node.params.map(&:name).join(", ") %>) = <%= node.name %>.new(<%= node.params.map(&:name).join(", ") %>, Location.null) <%- end -%> <%- tokens.each do |token| -%> diff --git a/config.yml b/config.yml new file mode 100644 index 0000000000..001f85c0cc --- /dev/null +++ b/config.yml @@ -0,0 +1,371 @@ +tokens: + - name: EOF + value: 0 + comment: final token in the file + - name: INVALID + comment: "an invalid token" + - name: AMPERSAND + comment: "&" + - name: AMPERSAND_AMPERSAND + comment: "&&" + - name: AMPERSAND_AMPERSAND_EQUAL + comment: "&&=" + - name: AMPERSAND_EQUAL + comment: "&=" + - name: BACK_REFERENCE + comment: "a back reference" + - name: BACKTICK + comment: "`" + - name: BANG + comment: "!" + - name: BANG_AT + comment: "!@" + - name: BANG_EQUAL + comment: "!=" + - name: BANG_TILDE + comment: "!~" + - name: BRACE_LEFT + comment: "{" + - name: BRACE_RIGHT + comment: "}" + - name: BRACKET_LEFT + comment: "[" + - name: BRACKET_LEFT_RIGHT + comment: "[]" + - name: BRACKET_RIGHT + comment: "]" + - name: CARET + comment: "^" + - name: CARET_EQUAL + comment: "^=" + - name: CHARACTER_LITERAL + comment: "a character literal" + - name: CLASS_VARIABLE + comment: "a class variable" + - name: COLON + comment: ":" + - name: COLON_COLON + comment: "::" + - name: COMMA + comment: "," + - name: COMMENT + comment: "a comment" + - name: CONSTANT + comment: "a constant" + - name: DOT + comment: "." + - name: DOT_DOT + comment: ".." + - name: DOT_DOT_DOT + comment: "..." + - name: EMBDOC_BEGIN + comment: "=begin" + - name: EMBDOC_END + comment: "=end" + - name: EMBDOC_LINE + comment: "a line inside of embedded documentation" + - name: EMBEXPR_BEGIN + comment: "#{" + - name: EMBEXPR_END + comment: "}" + - name: EQUAL + comment: "=" + - name: EQUAL_EQUAL + comment: "==" + - name: EQUAL_EQUAL_EQUAL + comment: "===" + - name: EQUAL_GREATER + comment: "=>" + - name: EQUAL_TILDE + comment: "=~" + - name: FLOAT + comment: "a floating point number" + - name: GREATER + comment: ">" + - name: GREATER_EQUAL + comment: ">=" + - name: GREATER_GREATER + comment: ">>" + - name: GREATER_GREATER_EQUAL + comment: ">>=" + - name: GLOBAL_VARIABLE + comment: "a global variable" + - name: IDENTIFIER + comment: "an identifier" + - name: IMAGINARY_NUMBER + comment: "an imaginary number literal" + - name: INSTANCE_VARIABLE + comment: "an instance variable" + - name: INTEGER + comment: "an integer (any base)" + - name: KEYWORD___ENCODING__ + comment: "__ENCODING__" + - name: KEYWORD___LINE__ + comment: "__LINE__" + - name: KEYWORD___FILE__ + comment: "__FILE__" + - name: KEYWORD_ALIAS + comment: "alias" + - name: KEYWORD_AND + comment: "and" + - name: KEYWORD_BEGIN + comment: "begin" + - name: KEYWORD_BEGIN_UPCASE + comment: "BEGIN" + - name: KEYWORD_BREAK + comment: "break" + - name: KEYWORD_CASE + comment: "case" + - name: KEYWORD_CLASS + comment: "class" + - name: KEYWORD_DEF + comment: "def" + - name: KEYWORD_DEFINED + comment: "defined?" + - name: KEYWORD_DO + comment: "do" + - name: KEYWORD_ELSE + comment: "else" + - name: KEYWORD_ELSIF + comment: "elsif" + - name: KEYWORD_END + comment: "end" + - name: KEYWORD_END_UPCASE + comment: "END" + - name: KEYWORD_ENSURE + comment: "ensure" + - name: KEYWORD_FALSE + comment: "false" + - name: KEYWORD_FOR + comment: "for" + - name: KEYWORD_IF + comment: "if" + - name: KEYWORD_IN + comment: "in" + - name: KEYWORD_MODULE + comment: "module" + - name: KEYWORD_NEXT + comment: "next" + - name: KEYWORD_NIL + comment: "nil" + - name: KEYWORD_NOT + comment: "not" + - name: KEYWORD_OR + comment: "or" + - name: KEYWORD_REDO + comment: "redo" + - name: KEYWORD_RESCUE + comment: "rescue" + - name: KEYWORD_RETRY + comment: "retry" + - name: KEYWORD_RETURN + comment: "return" + - name: KEYWORD_SELF + comment: "self" + - name: KEYWORD_SUPER + comment: "super" + - name: KEYWORD_THEN + comment: "then" + - name: KEYWORD_TRUE + comment: "true" + - name: KEYWORD_UNDEF + comment: "undef" + - name: KEYWORD_UNLESS + comment: "unless" + - name: KEYWORD_UNTIL + comment: "until" + - name: KEYWORD_WHEN + comment: "when" + - name: KEYWORD_WHILE + comment: "while" + - name: KEYWORD_YIELD + comment: "yield" + - name: LABEL + comment: "a label" + - name: LAMBDA_BEGIN + comment: "{" + - name: LESS + comment: "<" + - name: LESS_EQUAL + comment: "<=" + - name: LESS_EQUAL_GREATER + comment: "<=>" + - name: LESS_LESS + comment: "<<" + - name: LESS_LESS_EQUAL + comment: "<<=" + - name: MINUS + comment: "-" + - name: MINUS_AT + comment: "-@" + - name: MINUS_EQUAL + comment: "-=" + - name: MINUS_GREATER + comment: "->" + - name: NEWLINE + comment: "a newline character outside of other tokens" + - name: NTH_REFERENCE + comment: "an nth global variable reference" + - name: PARENTHESIS_LEFT + comment: "(" + - name: PARENTHESIS_RIGHT + comment: ")" + - name: PERCENT + comment: "%" + - name: PERCENT_EQUAL + comment: "%=" + - name: PERCENT_LOWER_I + comment: "%i" + - name: PERCENT_LOWER_W + comment: "%w" + - name: PERCENT_LOWER_X + comment: "%x" + - name: PERCENT_UPPER_I + comment: "%I" + - name: PERCENT_UPPER_W + comment: "%W" + - name: PIPE + comment: "|" + - name: PIPE_EQUAL + comment: "|=" + - name: PIPE_PIPE + comment: "||" + - name: PIPE_PIPE_EQUAL + comment: "||=" + - name: PLUS + comment: "+" + - name: PLUS_AT + comment: "+@" + - name: PLUS_EQUAL + comment: "+=" + - name: QUESTION_MARK + comment: "?" + - name: RATIONAL_NUMBER + comment: "a rational number literal" + - name: REGEXP_BEGIN + comment: "the beginning of a regular expression" + - name: REGEXP_END + comment: "the end of a regular expression" + - name: SEMICOLON + comment: ";" + - name: SLASH + comment: "/" + - name: SLASH_EQUAL + comment: "/=" + - name: STAR + comment: "*" + - name: STAR_EQUAL + comment: "*=" + - name: STAR_STAR + comment: "**" + - name: STAR_STAR_EQUAL + comment: "**=" + - name: STRING_BEGIN + comment: "the beginning of a string" + - name: STRING_CONTENT + comment: "the contents of a string" + - name: STRING_END + comment: "the end of a string" + - name: SYMBOL_BEGIN + comment: "the beginning of a symbol" + - name: TILDE + comment: "~" + - name: TILDE_AT + comment: "~@" + - name: WORDS_SEP + comment: "a separator between words in a list" +nodes: + - name: Assignment + child_nodes: + - node target + - token operator + - node value + location: target->value + - name: Binary + child_nodes: + - node left + - token operator + - node right + location: left->right + - name: CharacterLiteral + child_nodes: + - token value + location: value + - name: FloatLiteral + child_nodes: + - token value + location: value + - name: Identifier + child_nodes: + - token value + location: value + - name: IfModifier + child_nodes: + - node statement + - token keyword + - node predicate + location: statement->predicate + - name: ImaginaryLiteral + child_nodes: + - token value + location: value + - name: IntegerLiteral + child_nodes: + - token value + location: value + - name: OperatorAssignment + child_nodes: + - node target + - token operator + - node value + location: target->value + - name: Program + child_nodes: + - node statements + location: statements + - name: RationalLiteral + child_nodes: + - token value + location: value + - name: Redo + child_nodes: + - token value + location: value + - name: Retry + child_nodes: + - token value + location: value + - name: Statements + child_nodes: + - node[] body + location: body + - name: Ternary + child_nodes: + - node predicate + - token question_mark + - node true_expression + - token colon + - node false_expression + location: predicate->false_expression + - name: UnlessModifier + child_nodes: + - node statement + - token keyword + - node predicate + location: statement->predicate + - name: UntilModifier + child_nodes: + - node statement + - token keyword + - node predicate + location: statement->predicate + - name: VariableReference + child_nodes: + - token value + location: value + - name: WhileModifier + child_nodes: + - node statement + - token keyword + - node predicate + location: statement->predicate