NAME

Text::KDL::XS::Value - A KDL value: null, boolean, number or string, with optional type annotation

SYNOPSIS

my $v = $node->args->[0];             # or $node->prop('key')

$v->type;             # 'null' | 'bool' | 'number' | 'string'
$v->kind;             # for numbers: 'integer' | 'float' | 'string'; else undef
$v->type_annotation;  # e.g. 'u32' for (u32)42, else undef

$v->is_null;  $v->is_bool;  $v->is_number;  $v->is_string;

$v->value;            # the raw stored scalar
$v->as_perl;          # undef | 1/0 | number | string  (best native scalar)
$v->as_string;        # undef | 'true'/'false' | KDL number text | string
$v->as_number;        # undef | 1/0 | a native Perl number
$v->as_bignum;        # undef | 1/0 | Math::BigInt or Math::BigFloat (exact)

# Constructing values for emit_kdl:
Text::KDL::XS::Value->new(type => 'null');
Text::KDL::XS::Value->new(type => 'bool',   value => 1);
Text::KDL::XS::Value->new(type => 'number', value => 42);             # kind integer
Text::KDL::XS::Value->new(type => 'number', value => 2.5);            # kind float
Text::KDL::XS::Value->new(type => 'number', kind => 'string', value => '1e400');
Text::KDL::XS::Value->new(type => 'string', value => 'text', type_annotation => 'date');

DESCRIPTION

Every argument and every property value in a KDL document is one of four types: null, boolean, number or string, optionally preceded by a (type) annotation. Text::KDL::XS::Value carries exactly that information, without coercing it, so that a document can be inspected and written back without loss.

The object is a blessed hash with the keys type, kind, value and type_annotation. Editing $v->{value} in place is supported and is the simplest way to change a value before re-emitting; the emitter checks the edited value the same way "new" does and dies if it no longer fits its type and kind.

VALUE MODEL

KDL source                  type    kind     value (Perl)        as_perl
--------------------------  ------  -------  ------------------  ----------
#null (v1: null)            null    undef    undef               undef
#true (v1: true)            bool    undef    1                   1
#false (v1: false)          bool    undef    0                   0
42, 0xFF, 1_000             number  integer  IV 42, 255, 1000    same
4294967295,                 number  integer  IV or UV            same
  18446744073709551615
3.14, 1e3                   number  float    NV 3.14, 1000       same
#inf #-inf #nan             number  float    Inf, -Inf, NaN      same
1e400, 3.141592653589793,   number  string   the digits as text  the string
  18446744073709551616
"text", bare, #"raw"#       string  undef    character string    same

The kind of a number says how it is stored in Perl:

integer   no decimal point or exponent, and the value lies in
          -2**63 .. 2**64-1 (values above 2**63-1 are unsigned integers)
float     decimal point or exponent, at most 15 digits written before
          the exponent (leading and trailing zeros count), written
          exponent within -284 .. 284; also #inf, #-inf and #nan. The
          value is the double nearest to the literal.
string    every other number, as text (underscores removed, radix
          prefixes converted to decimal, leading + dropped, otherwise
          verbatim)

So 0xFFFFFFFF and Unix timestamps are integers, while 3.141592653589793 (16 digits) and 18446744073709551616 (2**64) arrive as string. The float rule is the one of the underlying ckdl library; a decimal kept as text is exact, see "ARBITRARY PRECISION NUMBERS" for how to use it.

CONSTRUCTOR

new

my $v = Text::KDL::XS::Value->new(type => $type, %fields);

The constructor checks its arguments, so that a value that was created successfully is always written as valid KDL.

type (required)

One of 'null', 'bool', 'number', 'string'. Missing dies with Text::KDL::XS::Value->new: 'type' is required, anything else with Text::KDL::XS::Value->new: unknown type 'X' (expected null, bool, number or string).

value

The payload, by type:

null     ignored; the value is always undef
bool     any Perl value, judged by Perl truthiness (so the string
         'false' means true); stored as 1 or 0
number   a Perl number, or the number as text (see kind); required
string   a character string; required

An object with string overloading is stringified once, here. A missing value for a number or string, and any other reference, die.

kind

For numbers only; any other type dies when kind is given. One of:

integer  a Perl integer, or decimal digits with an optional sign, in the
         range -2**63 .. 2**64-1 (written in decimal)
float    anything Perl considers numeric (Scalar::Util::looks_like_number);
         written with the shortest text that reads back as the same double
string   a KDL number literal, written verbatim: an optional sign followed
         by decimal digits with an optional fraction and exponent, or by
         0x, 0o or 0b digits, '_' allowed after the first digit; or one of
         #inf, #-inf and #nan

Without kind, it is inferred from value: a Perl number (a scalar with a numeric value and no string value, or one whose string value is exactly Perl's rendering of that number) is integer or float, other text that is a KDL number literal is string, and anything else dies.

'string' is the way to write arbitrary precision numbers and floats with exactly the digits you want (see "Emitting floating point numbers" in Text::KDL::XS::Cookbook).

type_annotation

Optional (type) annotation string.

Any other field and an odd number of arguments die. new may be called on a subclass.

METHODS

type

'null', 'bool', 'number' or 'string'.

kind

For numbers: 'integer', 'float' or 'string'. undef for the other types.

type_annotation

The (type) annotation written before the value, as a string, or undef.

is_null, is_bool, is_number, is_string

True when type is the corresponding type.

value

The stored scalar exactly as the parser produced it (or as passed to new): undef for null, 1/0 for booleans, an integer or floating point number for numbers, the digit string for numbers of kind string, the text for strings.

as_perl

The most natural Perl representation:

null    -> undef
bool    -> 1 or 0
number  -> integer / float (or the digit string for kind 'string')
string  -> the string

This is what "as_data" in Text::KDL::XS::Node uses.

as_string

A string form for display or comparison:

null    -> undef
bool    -> 'true' or 'false'
number  -> integer: the stored value as a string
           float: the text the emitter writes, the shortest one that
           reads back as the same double, always with a decimal point
           or an exponent ('1.0', '1000.0', '0.30000000000000004',
           '1e+21'); '#inf', '#-inf' or '#nan' for the special values
           kind 'string': the stored text
string  -> the string

as_number

A native Perl number for arithmetic:

null    -> undef
bool    -> 1 or 0
number  -> the number (kind integer / float, unchanged, -0.0 included);
           for kind 'string' the text converted to a Perl number:
           radix prefixes and underscores are understood, #inf, #-inf
           and #nan give Inf, -Inf and NaN
string  -> the string numified (a non-numeric string gives 0 and an
           "isn't numeric" warning)

Numbers kept as text are usually too big or too precise for a Perl number, so the conversion is lossy: integers beyond 2**64 and decimals with more than about 16 digits lose precision, values beyond the range of a double become infinite. Use "as_bignum" for exact arithmetic.

as_bignum

An exact arbitrary precision number:

null    -> undef
bool    -> 1 or 0
number  -> a Math::BigInt for integral text (kind integer, or kind
           string without a decimal point or exponent), a Math::BigFloat
           otherwise (floats, decimals, #inf, #-inf, #nan)
string  -> dies

The object is built from the same text as "as_string", so a float gives the decimal it is written as (0.1 gives 0.1, not the binary value of the double). Math::BigInt and Math::BigFloat are loaded on first use.

ARBITRARY PRECISION NUMBERS

Numbers outside the native integer range, and decimals with more digits than a double holds, have kind string and keep their exact text:

my $v = parse_kdl("n 123456789012345678901234567890\n")->nodes->[0]->args->[0];
$v->kind;                  # 'string'
$v->value;                 # '123456789012345678901234567890'
$v->as_bignum + 1;         # Math::BigInt 123456789012345678901234567891
$v->as_number;             # 1.23456789012346e+29 (a double, inexact)

The stored text is normalised: underscores removed, hexadecimal, octal and binary literals converted to decimal, a leading + dropped, a - preserved. For decimal literals with a point or exponent the original spelling is kept (1e400, 3.141592653589793).

SEE ALSO

Text::KDL::XS, Text::KDL::XS::Node, "NUMBERS" in Text::KDL::XS::Cookbook.

AUTHOR

Davenonymous <perl@davenonymous.com>

LICENSE

Copyright (C) 2026 Davenonymous.

This Perl distribution is licensed under the same terms as Perl itself.