[ruby/prism] Parse float values

https://github.com/ruby/prism/commit/9137226a52
This commit is contained in:
Kevin Newton 2024-02-22 15:53:28 -05:00
parent 3b3def5db7
commit 5e0589cf52
30 changed files with 199 additions and 22 deletions

View File

@ -57,13 +57,6 @@ module Prism
private_constant :HeredocQuery
class FloatNode < Node
# Returns the value of the node as a Ruby Float.
def value
Float(slice)
end
end
class ImaginaryNode < Node
# Returns the value of the node as a Ruby Complex.
def value

View File

@ -1396,6 +1396,10 @@ nodes:
baz if foo .. bar
^^^^^^^^^^
- name: FloatNode
fields:
- name: value
type: double
comment: The value of the floating point number as a Float.
comment: |
Represents a floating point number literal.

View File

@ -179,6 +179,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_EXPECT_STRING_CONTENT] = { "expected string content after opening string delimiter", PM_ERROR_LEVEL_FATAL },
[PM_ERR_EXPECT_WHEN_DELIMITER] = { "expected a delimiter after the predicates of a `when` clause", PM_ERROR_LEVEL_FATAL },
[PM_ERR_EXPRESSION_BARE_HASH] = { "unexpected bare hash in expression", PM_ERROR_LEVEL_FATAL },
[PM_ERR_FLOAT_PARSE] = { "could not parse the float '%.*s'", PM_ERROR_LEVEL_FATAL },
[PM_ERR_FOR_COLLECTION] = { "expected a collection after the `in` in a `for` statement", PM_ERROR_LEVEL_FATAL },
[PM_ERR_FOR_INDEX] = { "expected an index after `for`", PM_ERROR_LEVEL_FATAL },
[PM_ERR_FOR_IN] = { "expected an `in` after the index in a `for` statement", PM_ERROR_LEVEL_FATAL },
@ -307,6 +308,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_WARN_AMBIGUOUS_SLASH] = { "ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_EQUAL_IN_CONDITIONAL] = { "found `= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_END_IN_METHOD] = { "END in method; use at_exit", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_FLOAT_OUT_OF_RANGE] = { "Float %.*s%s out of range", PM_WARNING_LEVEL_VERBOSE }
};
static inline const char *

View File

@ -176,6 +176,7 @@ typedef enum {
PM_ERR_EXPECT_STRING_CONTENT,
PM_ERR_EXPECT_WHEN_DELIMITER,
PM_ERR_EXPRESSION_BARE_HASH,
PM_ERR_FLOAT_PARSE,
PM_ERR_FOR_COLLECTION,
PM_ERR_FOR_IN,
PM_ERR_FOR_INDEX,
@ -305,6 +306,7 @@ typedef enum {
PM_WARN_AMBIGUOUS_SLASH,
PM_WARN_EQUAL_IN_CONDITIONAL,
PM_WARN_END_IN_METHOD,
PM_WARN_FLOAT_OUT_OF_RANGE,
// This is the number of diagnostic codes.
PM_DIAGNOSTIC_ID_LEN,

View File

@ -3138,6 +3138,70 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
return node;
}
/**
* Parse the value of a double, add appropriate errors if there is an issue, and
* return the value that should be saved on the PM_FLOAT_NODE node.
*/
static double
pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
ptrdiff_t diff = token->end - token->start;
if (diff <= 0) return 0.0;
// First, get a buffer of the content.
size_t length = (size_t) diff;
char *buffer = malloc(sizeof(char) * (length + 1));
memcpy((void *) buffer, token->start, length);
// Next, handle underscores by removing them from the buffer.
for (size_t index = 0; index < length; index++) {
if (buffer[index] == '_') {
memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
length--;
}
}
// Null-terminate the buffer so that strtod cannot read off the end.
buffer[length] = '\0';
// Now, call strtod to parse the value. Note that CRuby has their own
// version of strtod which avoids locales. We're okay using the locale-aware
// version because we've already validated through the parser that the token
// is in a valid format.
errno = 0;
char *eptr;
double value = strtod(buffer, &eptr);
// This should never happen, because we've already checked that the token
// is in a valid format. However it's good to be safe.
if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
free((void *) buffer);
return 0.0;
}
// If errno is set, then it should only be ERANGE. At this point we need to
// check if it's infinity (it should be).
if (errno == ERANGE) {
int warn_width;
const char *ellipsis;
if (length > 20) {
warn_width = 20;
ellipsis = "...";
} else {
warn_width = (int) length;
ellipsis = "";
}
pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
value = (value < 0x0) ? -HUGE_VAL : HUGE_VAL;
}
// Finally we can free the buffer and return the value.
free((void *) buffer);
return value;
}
/**
* Allocate and initialize a new FloatNode node.
*/
@ -3146,11 +3210,14 @@ pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
assert(token->type == PM_TOKEN_FLOAT);
pm_float_node_t *node = PM_ALLOC_NODE(parser, pm_float_node_t);
*node = (pm_float_node_t) {{
*node = (pm_float_node_t) {
{
.type = PM_FLOAT_NODE,
.flags = PM_NODE_FLAG_STATIC_LITERAL,
.location = PM_LOCATION_TOKEN_VALUE(token)
}};
},
.value = pm_double_parse(parser, token)
};
return node;
}
@ -14293,13 +14360,18 @@ parse_pattern(pm_parser_t *parser, bool top_pattern, pm_diagnostic_id_t diag_id)
static inline void
parse_negative_numeric(pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE:
node->location.start--;
((pm_integer_node_t *) node)->value.negative = true;
case PM_INTEGER_NODE: {
pm_integer_node_t *cast = (pm_integer_node_t *) node;
cast->base.location.start--;
cast->value.negative = true;
break;
case PM_FLOAT_NODE:
node->location.start--;
}
case PM_FLOAT_NODE: {
pm_float_node_t *cast = (pm_float_node_t *) node;
cast->base.location.start--;
cast->value = -cast->value;
break;
}
case PM_RATIONAL_NODE:
node->location.start--;
parse_negative_numeric(((pm_rational_node_t *) node)->numeric);

View File

@ -25,6 +25,7 @@
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>

View File

@ -213,6 +213,9 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
<%- when Prism::IntegerField -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
argv[<%= index %>] = pm_integer_new(&cast-><%= field.name %>);
<%- when Prism::DoubleField -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
argv[<%= index %>] = DBL2NUM(cast-><%= field.name %>);
<%- else -%>
<%- raise -%>
<%- end -%>

View File

@ -185,6 +185,7 @@ typedef struct pm_<%= node.human %> {
when Prism::UInt8Field then "uint8_t #{field.name}"
when Prism::UInt32Field then "uint32_t #{field.name}"
when Prism::IntegerField then "pm_integer_t #{field.name}"
when Prism::DoubleField then "double #{field.name}"
else raise field.class.name
end
%>;

View File

@ -133,7 +133,7 @@ module Prism
else
table.field("<%= field.name %>", "[]")
end
<%- when Prism::StringField, Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt8Field, Prism::UInt32Field, Prism::ConstantListField, Prism::IntegerField -%>
<%- when Prism::StringField, Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt8Field, Prism::UInt32Field, Prism::ConstantListField, Prism::IntegerField, Prism::DoubleField -%>
table.field("<%= field.name %>", node.<%= field.name %>.inspect)
<%- when Prism::LocationField -%>
table.field("<%= field.name %>", location_inspect(node.<%= field.name %>))

View File

@ -281,7 +281,7 @@ module Prism
inspector << "<%= pointer %><%= field.name %>:\n"
inspector << <%= field.name %>.inspect(inspector.child_inspector("<%= preadd %>")).delete_prefix(inspector.prefix)
end
<%- when Prism::ConstantField, Prism::StringField, Prism::UInt8Field, Prism::UInt32Field, Prism::IntegerField -%>
<%- when Prism::ConstantField, Prism::StringField, Prism::UInt8Field, Prism::UInt32Field, Prism::IntegerField, Prism::DoubleField -%>
inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
<%- when Prism::OptionalConstantField -%>
if (<%= field.name %> = self.<%= field.name %>).nil?

View File

@ -183,6 +183,10 @@ module Prism
value
end
def load_double
io.read(8).unpack1("D")
end
def load_serialized_length
io.read(4).unpack1("L")
end
@ -300,6 +304,7 @@ module Prism
when Prism::UInt8Field then "io.getbyte"
when Prism::UInt32Field, Prism::FlagsField then "load_varuint"
when Prism::IntegerField then "load_integer"
when Prism::DoubleField then "load_double"
else raise
end
} + ["location"]).join(", ") -%>)
@ -336,6 +341,7 @@ module Prism
when Prism::UInt8Field then "io.getbyte"
when Prism::UInt32Field, Prism::FlagsField then "load_varuint"
when Prism::IntegerField then "load_integer"
when Prism::DoubleField then "load_double"
else raise
end
} + ["location"]).join(", ") -%>)

View File

@ -56,12 +56,12 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) {
<%- nodes.each do |node| -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
case <%= node.type %>: {
<%- if node.fields.any? { |field| ![Prism::LocationField, Prism::OptionalLocationField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField].include?(field.class) } -%>
<%- if node.fields.any? { |field| ![Prism::LocationField, Prism::OptionalLocationField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField, Prism::DoubleField].include?(field.class) } -%>
pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
<%- end -%>
<%- node.fields.each do |field| -%>
<%- case field -%>
<%- when Prism::LocationField, Prism::OptionalLocationField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField -%>
<%- when Prism::LocationField, Prism::OptionalLocationField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField, Prism::DoubleField -%>
<%- when Prism::NodeField -%>
pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
<%- when Prism::OptionalNodeField -%>
@ -107,7 +107,7 @@ pm_node_memsize_node(pm_node_t *node, pm_memsize_t *memsize) {
memsize->memsize += sizeof(*cast);
<%- node.fields.each do |field| -%>
<%- case field -%>
<%- when Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::LocationField, Prism::OptionalLocationField -%>
<%- when Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt8Field, Prism::UInt32Field, Prism::FlagsField, Prism::LocationField, Prism::OptionalLocationField, Prism::DoubleField -%>
<%- when Prism::NodeField -%>
pm_node_memsize_node((pm_node_t *)cast-><%= field.name %>, memsize);
<%- when Prism::OptionalNodeField -%>
@ -276,6 +276,8 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no
pm_buffer_append_string(buffer, "]}", 2);
}
}
<%- when Prism::DoubleField -%>
pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>);
<%- else -%>
<%- raise %>
<%- end -%>

View File

@ -156,6 +156,8 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
}
pm_buffer_append_string(output_buffer, "]\n", 2);
}
<%- when Prism::DoubleField -%>
pm_buffer_append_format(output_buffer, " %f\n", cast-><%= field.name %>);
<%- else -%>
<%- raise -%>
<%- end -%>

View File

@ -127,6 +127,8 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK));
<%- when Prism::IntegerField -%>
pm_serialize_integer(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
<%- when Prism::DoubleField -%>
pm_buffer_append_double(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
<%- else -%>
<%- raise -%>
<%- end -%>

View File

@ -270,6 +270,22 @@ module Prism
end
end
# This represents a double-precision floating point number. When it gets to
# Ruby it will be a Float.
class DoubleField < Field
def rbs_class
"Float"
end
def rbi_class
"Float"
end
def java_type
"double"
end
end
# This class represents a node in the tree, configured by the config.yml file
# in YAML format. It contains information about the name of the node and the
# various child nodes it contains.
@ -332,6 +348,7 @@ module Prism
when "uint32" then UInt32Field
when "flags" then FlagsField
when "integer" then IntegerField
when "double" then DoubleField
else raise("Unknown field type: #{name.inspect}")
end
end

View File

@ -163,6 +163,15 @@ pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
pm_buffer_append_varuint(buffer, unsigned_int);
}
/**
* Append a double to the buffer.
*/
void
pm_buffer_append_double(pm_buffer_t *buffer, double value) {
const void *source = &value;
pm_buffer_append(buffer, source, sizeof(double));
}
/**
* Append a slice of source code to the buffer.
*/

View File

@ -129,6 +129,14 @@ void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value);
*/
void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
/**
* Append a double to the buffer.
*
* @param buffer The buffer to append to.
* @param value The double to append.
*/
void pm_buffer_append_double(pm_buffer_t *buffer, double value);
/**
* The different types of escaping that can be performed by the buffer when
* appending a slice of Ruby source code.

View File

@ -10,6 +10,7 @@
│ ├── flags: decimal
│ └── value: 1
├── @ FloatNode (location: (5,0)-(5,3))
│ └── value: 1.0
├── @ IntegerNode (location: (7,0)-(7,1))
│ ├── flags: decimal
│ └── value: 2
@ -81,11 +82,13 @@
├── @ RationalNode (location: (47,0)-(47,4))
│ └── numeric:
│ @ FloatNode (location: (47,0)-(47,3))
│ └── value: 1.2
├── @ ImaginaryNode (location: (49,0)-(49,5))
│ └── numeric:
│ @ RationalNode (location: (49,0)-(49,4))
│ └── numeric:
│ @ FloatNode (location: (49,0)-(49,3))
│ └── value: 1.2
├── @ ImaginaryNode (location: (51,0)-(51,4))
│ └── numeric:
│ @ RationalNode (location: (51,0)-(51,3))
@ -96,11 +99,13 @@
├── @ RationalNode (location: (53,0)-(53,5))
│ └── numeric:
│ @ FloatNode (location: (53,0)-(53,4))
│ └── value: -1.2
├── @ ImaginaryNode (location: (55,0)-(55,6))
│ └── numeric:
│ @ RationalNode (location: (55,0)-(55,5))
│ └── numeric:
│ @ FloatNode (location: (55,0)-(55,4))
│ └── value: -1.2
├── @ RationalNode (location: (57,0)-(57,4))
│ └── numeric:
│ @ IntegerNode (location: (57,0)-(57,3))

View File

@ -51,6 +51,7 @@
│ │ └── block: ∅
│ ├── pattern:
│ │ @ FloatNode (location: (3,7)-(3,10))
│ │ └── value: 1.0
│ └── operator_loc: (3,4)-(3,6) = "=>"
├── @ MatchRequiredNode (location: (4,0)-(4,9))
│ ├── value:
@ -544,8 +545,10 @@
│ │ ├── flags: ∅
│ │ ├── left:
│ │ │ @ FloatNode (location: (29,7)-(29,10))
│ │ │ └── value: 1.0
│ │ ├── right:
│ │ │ @ FloatNode (location: (29,14)-(29,17))
│ │ │ └── value: 1.0
│ │ └── operator_loc: (29,11)-(29,13) = ".."
│ └── operator_loc: (29,4)-(29,6) = "=>"
├── @ MatchRequiredNode (location: (30,0)-(30,15))
@ -2426,6 +2429,7 @@
│ │ └── block: ∅
│ ├── pattern:
│ │ @ FloatNode (location: (106,7)-(106,10))
│ │ └── value: 1.0
│ └── operator_loc: (106,4)-(106,6) = "in"
├── @ MatchPredicateNode (location: (107,0)-(107,9))
│ ├── value:
@ -2966,6 +2970,7 @@
│ │ └── @ InNode (location: (137,10)-(137,21))
│ │ ├── pattern:
│ │ │ @ FloatNode (location: (137,13)-(137,16))
│ │ │ └── value: 1.0
│ │ ├── statements: ∅
│ │ ├── in_loc: (137,10)-(137,12) = "in"
│ │ └── then_loc: (137,17)-(137,21) = "then"
@ -3681,6 +3686,7 @@
│ │ │ │ @ StatementsNode (location: (164,13)-(164,16))
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ FloatNode (location: (164,13)-(164,16))
│ │ │ │ └── value: 1.0
│ │ │ ├── consequent: ∅
│ │ │ └── end_keyword_loc: ∅
│ │ ├── statements: ∅

View File

@ -12,5 +12,6 @@
│ @ StatementsNode (location: (1,0)-(1,3))
│ └── body: (length: 1)
│ └── @ FloatNode (location: (1,0)-(1,3))
│ └── value: 1.0
├── consequent: ∅
└── end_keyword_loc: ∅

View File

@ -4,3 +4,4 @@
@ StatementsNode (location: (1,0)-(1,4))
└── body: (length: 1)
└── @ FloatNode (location: (1,0)-(1,4))
└── value: -0.0

View File

@ -144,6 +144,7 @@
│ │ │ ├── flags: decimal
│ │ │ └── value: 1
│ │ ├── @ FloatNode (location: (29,4)-(29,7))
│ │ │ └── value: 1.0
│ │ ├── @ RationalNode (location: (29,9)-(29,11))
│ │ │ └── numeric:
│ │ │ @ IntegerNode (location: (29,9)-(29,10))

View File

@ -319,9 +319,11 @@
├── @ RationalNode (location: (20,0)-(20,4))
│ └── numeric:
│ @ FloatNode (location: (20,0)-(20,3))
│ └── value: 1.5
├── @ RationalNode (location: (21,0)-(21,4))
│ └── numeric:
│ @ FloatNode (location: (21,0)-(21,3))
│ └── value: 1.3
├── @ ImaginaryNode (location: (22,0)-(22,2))
│ └── numeric:
│ @ IntegerNode (location: (22,0)-(22,1))
@ -335,9 +337,11 @@
├── @ ImaginaryNode (location: (24,0)-(24,4))
│ └── numeric:
│ @ FloatNode (location: (24,0)-(24,3))
│ └── value: 0.6
├── @ ImaginaryNode (location: (25,0)-(25,5))
│ └── numeric:
│ @ FloatNode (location: (25,0)-(25,4))
│ └── value: -0.6
├── @ ImaginaryNode (location: (26,0)-(26,32))
│ └── numeric:
│ @ IntegerNode (location: (26,0)-(26,31))
@ -711,6 +715,7 @@
│ │ │ ├── flags: ∅
│ │ │ ├── receiver:
│ │ │ │ @ FloatNode (location: (60,1)-(60,4))
│ │ │ │ └── value: 0.0
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :/
│ │ │ ├── message_loc: (60,5)-(60,6) = "/"
@ -720,6 +725,7 @@
│ │ │ │ ├── flags: ∅
│ │ │ │ └── arguments: (length: 1)
│ │ │ │ └── @ FloatNode (location: (60,7)-(60,10))
│ │ │ │ └── value: 0.0
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── opening_loc: (60,0)-(60,1) = "("
@ -744,6 +750,7 @@
│ │ │ ├── flags: ∅
│ │ │ ├── receiver:
│ │ │ │ @ FloatNode (location: (61,4)-(61,7))
│ │ │ │ └── value: 0.0
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :/
│ │ │ ├── message_loc: (61,8)-(61,9) = "/"
@ -753,6 +760,7 @@
│ │ │ │ ├── flags: ∅
│ │ │ │ └── arguments: (length: 1)
│ │ │ │ └── @ FloatNode (location: (61,10)-(61,13))
│ │ │ │ └── value: 0.0
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── opening_loc: (61,3)-(61,4) = "("
@ -769,6 +777,7 @@
│ │ │ ├── flags: ∅
│ │ │ ├── receiver:
│ │ │ │ @ FloatNode (location: (62,1)-(62,4))
│ │ │ │ └── value: 0.0
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :/
│ │ │ ├── message_loc: (62,5)-(62,6) = "/"
@ -778,6 +787,7 @@
│ │ │ │ ├── flags: ∅
│ │ │ │ └── arguments: (length: 1)
│ │ │ │ └── @ FloatNode (location: (62,7)-(62,10))
│ │ │ │ └── value: 0.0
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── opening_loc: (62,0)-(62,1) = "("
@ -788,7 +798,9 @@
│ │ └── value: 100
│ └── operator_loc: (62,11)-(62,13) = ".."
├── @ FloatNode (location: (63,0)-(63,4))
│ └── value: -0.1
├── @ FloatNode (location: (64,0)-(64,3))
│ └── value: 0.1
├── @ ArrayNode (location: (65,0)-(65,6))
│ ├── flags: ∅
│ ├── elements: (length: 2)

View File

@ -6,6 +6,7 @@
├── @ RationalNode (location: (1,0)-(1,4))
│ └── numeric:
│ @ FloatNode (location: (1,0)-(1,3))
│ └── value: 1.0
├── @ RationalNode (location: (2,0)-(2,3))
│ └── numeric:
│ @ IntegerNode (location: (2,0)-(2,2))
@ -18,8 +19,11 @@
│ ├── flags: decimal
│ └── value: 1000
├── @ FloatNode (location: (5,0)-(5,4))
│ └── value: 10000000000.0
├── @ FloatNode (location: (6,0)-(6,14))
│ └── value: Infinity
├── @ FloatNode (location: (7,0)-(7,15))
│ └── value: -Infinity
├── @ StringNode (location: (8,0)-(8,2))
│ ├── flags: ∅
│ ├── opening_loc: (8,0)-(8,1) = "?"
@ -58,7 +62,9 @@
│ │ └── unescaped: "baz"
│ └── closing_loc: (11,13)-(11,14) = ")"
├── @ FloatNode (location: (12,0)-(12,16))
│ └── value: Infinity
├── @ FloatNode (location: (13,0)-(13,17))
│ └── value: -Infinity
└── @ CallNode (location: (14,0)-(14,10))
├── flags: ignore_visibility
├── receiver: ∅

View File

@ -6,11 +6,13 @@
├── @ ImaginaryNode (location: (1,0)-(1,5))
│ └── numeric:
│ @ FloatNode (location: (1,0)-(1,4))
│ └── value: 42.1
├── @ ImaginaryNode (location: (3,0)-(3,6))
│ └── numeric:
│ @ RationalNode (location: (3,0)-(3,5))
│ └── numeric:
│ @ FloatNode (location: (3,0)-(3,4))
│ └── value: 42.1
├── @ ImaginaryNode (location: (5,0)-(5,3))
│ └── numeric:
│ @ IntegerNode (location: (5,0)-(5,2))

View File

@ -4,4 +4,6 @@
@ StatementsNode (location: (1,0)-(3,4))
└── body: (length: 2)
├── @ FloatNode (location: (1,0)-(1,5))
│ └── value: -1.33
└── @ FloatNode (location: (3,0)-(3,4))
└── value: 1.33

View File

@ -22,6 +22,7 @@
│ │ │ │ @ StatementsNode (location: (1,5)-(1,9))
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ FloatNode (location: (1,5)-(1,9))
│ │ │ │ └── value: -1.3
│ │ │ ├── opening_loc: (1,4)-(1,5) = "("
│ │ │ └── closing_loc: (1,9)-(1,10) = ")"
│ │ ├── call_operator_loc: (1,10)-(1,11) = "."
@ -52,6 +53,7 @@
│ │ │ @ StatementsNode (location: (3,6)-(3,10))
│ │ │ └── body: (length: 1)
│ │ │ └── @ FloatNode (location: (3,6)-(3,10))
│ │ │ └── value: -1.3
│ │ ├── opening_loc: (3,5)-(3,6) = "("
│ │ └── closing_loc: (3,10)-(3,11) = ")"
│ ├── call_operator_loc: (3,11)-(3,12) = "."

View File

@ -6,6 +6,7 @@
├── @ RationalNode (location: (1,0)-(1,5))
│ └── numeric:
│ @ FloatNode (location: (1,0)-(1,4))
│ └── value: 42.1
└── @ RationalNode (location: (3,0)-(3,3))
└── numeric:
@ IntegerNode (location: (3,0)-(3,2))

View File

@ -109,6 +109,7 @@
│ │ │ ├── closing_loc: (3,7)-(3,8) = ")"
│ │ │ └── block: ∅
│ │ └── @ FloatNode (location: (3,10)-(3,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (3,14)-(3,20))
@ -167,6 +168,7 @@
│ │ └── @ ImaginaryNode (location: (5,10)-(5,14))
│ │ └── numeric:
│ │ @ FloatNode (location: (5,10)-(5,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (5,15)-(5,21))
@ -225,6 +227,7 @@
│ │ └── @ RationalNode (location: (7,10)-(7,14))
│ │ └── numeric:
│ │ @ FloatNode (location: (7,10)-(7,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (7,15)-(7,21))
@ -400,6 +403,7 @@
│ │ │ ├── closing_loc: (13,8)-(13,9) = ")"
│ │ │ └── block: ∅
│ │ └── @ FloatNode (location: (13,11)-(13,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (13,15)-(13,21))
@ -458,6 +462,7 @@
│ │ └── @ ImaginaryNode (location: (15,11)-(15,15))
│ │ └── numeric:
│ │ @ FloatNode (location: (15,11)-(15,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (15,16)-(15,22))
@ -516,6 +521,7 @@
│ │ └── @ RationalNode (location: (17,11)-(17,15))
│ │ └── numeric:
│ │ @ FloatNode (location: (17,11)-(17,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (17,16)-(17,22))
@ -701,6 +707,7 @@
│ │ │ ├── opening_loc: (23,3)-(23,4) = "{"
│ │ │ └── closing_loc: (23,7)-(23,8) = "}"
│ │ └── @ FloatNode (location: (23,10)-(23,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (23,14)-(23,20))
@ -764,6 +771,7 @@
│ │ └── @ ImaginaryNode (location: (25,10)-(25,14))
│ │ └── numeric:
│ │ @ FloatNode (location: (25,10)-(25,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (25,15)-(25,21))
@ -827,6 +835,7 @@
│ │ └── @ RationalNode (location: (27,10)-(27,14))
│ │ └── numeric:
│ │ @ FloatNode (location: (27,10)-(27,13))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (27,15)-(27,21))
@ -1017,6 +1026,7 @@
│ │ │ ├── opening_loc: (33,3)-(33,4) = "{"
│ │ │ └── closing_loc: (33,8)-(33,9) = "}"
│ │ └── @ FloatNode (location: (33,11)-(33,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (33,15)-(33,21))
@ -1080,6 +1090,7 @@
│ │ └── @ ImaginaryNode (location: (35,11)-(35,15))
│ │ └── numeric:
│ │ @ FloatNode (location: (35,11)-(35,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (35,16)-(35,22))
@ -1143,6 +1154,7 @@
│ │ └── @ RationalNode (location: (37,11)-(37,15))
│ │ └── numeric:
│ │ @ FloatNode (location: (37,11)-(37,14))
│ │ └── value: 1.0
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (37,16)-(37,22))

View File

@ -7,6 +7,7 @@
│ ├── flags: ∅
│ ├── receiver:
│ │ @ FloatNode (location: (1,0)-(1,4))
│ │ └── value: 2.0
│ ├── call_operator_loc: ∅
│ ├── name: :**
│ ├── message_loc: (1,5)-(1,7) = "**"
@ -56,6 +57,7 @@
│ ├── flags: ∅
│ ├── receiver:
│ │ @ FloatNode (location: (5,1)-(5,4))
│ │ └── value: 2.0
│ ├── call_operator_loc: ∅
│ ├── name: :**
│ ├── message_loc: (5,5)-(5,7) = "**"