New Upstream Release - ruby-tomlrb

Ready changes

Summary

Merged new upstream version: 2.0.3 (was: 1.3.0).

Resulting package

Built on 2022-10-17T22:49 (took 5m53s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ruby-tomlrb

Lintian Result

Diff

diff --git a/debian/changelog b/debian/changelog
index 31d9fef..ab5e3b4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,10 @@
-ruby-tomlrb (1.3.0-3) UNRELEASED; urgency=medium
+ruby-tomlrb (2.0.3-1) UNRELEASED; urgency=medium
 
   * Set upstream metadata fields: Repository-Browse.
   * Update standards version to 4.6.1, no changes needed.
+  * New upstream release.
 
- -- Debian Janitor <janitor@jelmer.uk>  Mon, 17 Oct 2022 11:57:20 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 17 Oct 2022 22:43:53 -0000
 
 ruby-tomlrb (1.3.0-2) unstable; urgency=medium
 
diff --git a/lib/tomlrb.rb b/lib/tomlrb.rb
index 63e4e09..3a48631 100644
--- a/lib/tomlrb.rb
+++ b/lib/tomlrb.rb
@@ -1,6 +1,9 @@
 require 'time'
 require 'stringio'
 require "tomlrb/version"
+require 'tomlrb/local_date_time'
+require 'tomlrb/local_date'
+require 'tomlrb/local_time'
 require 'tomlrb/string_utils'
 require "tomlrb/scanner"
 require "tomlrb/parser"
diff --git a/lib/tomlrb/generated_parser.rb b/lib/tomlrb/generated_parser.rb
index edbcbe0..f2e3fb5 100644
--- a/lib/tomlrb/generated_parser.rb
+++ b/lib/tomlrb/generated_parser.rb
@@ -1,7 +1,7 @@
 #
 # DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.4.16.pre.1
-# from Racc grammer file "".
+# This file is automatically generated by Racc 1.6.0
+# from Racc grammar file "".
 #
 
 require 'racc/parser.rb'
@@ -10,160 +10,185 @@ module Tomlrb
 ##### State transition tables begin ###
 
 racc_action_table = [
-     2,    17,    11,    31,    12,    31,    13,    79,    14,    40,
-    41,    80,    15,    16,     8,    71,    72,    10,    27,    29,
-    32,    29,    59,    60,    61,    62,    58,    55,    52,    53,
-    54,    56,    57,    46,    33,    34,    10,    59,    60,    61,
-    62,    58,    55,    52,    53,    54,    56,    57,    46,    35,
-    36,    10,    59,    60,    61,    62,    58,    55,    52,    53,
-    54,    56,    57,    46,    37,    38,    10,    59,    60,    61,
-    62,    58,    55,    52,    53,    54,    56,    57,    46,    43,
-    68,    10,    59,    60,    61,    62,    58,    55,    52,    53,
-    54,    56,    57,    46,   nil,   nil,    10,    59,    60,    61,
-    62,    58,    55,    52,    53,    54,    56,    57,    46,   nil,
-   nil,    10,    59,    60,    61,    62,    58,    55,    52,    53,
-    54,    56,    57,    46,   nil,   nil,    10,    59,    60,    61,
-    62,    58,    55,    52,    53,    54,    56,    57,    46,    75,
-   nil,    10,    59,    60,    61,    62,    58,    55,    52,    53,
-    54,    56,    57,    46,    75,    21,    10,    22,   nil,    23,
-   nil,    24,   nil,   nil,   nil,    25,    26,    21,    19,    22,
-   nil,    23,   nil,    24,   nil,   nil,   nil,    25,    26,   nil,
-    19 ]
+     2,    45,    16,    56,    17,    44,    18,    55,    23,    19,
+    20,    14,    21,    22,     8,     4,    10,    36,    16,    12,
+    17,    48,    18,    46,    47,    19,    20,    42,    21,    22,
+    50,    51,    87,    86,    39,    54,    39,    72,    73,    74,
+    75,    70,    71,    67,    68,    65,    66,    69,    78,   nil,
+    59,   nil,   nil,    12,    72,    73,    74,    75,    70,    71,
+    67,    68,    65,    66,    69,   nil,   nil,    59,   nil,   nil,
+    12,    72,    73,    74,    75,    70,    71,    67,    68,    65,
+    66,    69,    91,   nil,    59,    89,   nil,    12,    72,    73,
+    74,    75,    70,    71,    67,    68,    65,    66,    69,    91,
+   nil,    59,    89,   nil,    12,    72,    73,    74,    75,    70,
+    71,    67,    68,    65,    66,    69,    91,   nil,    59,    89,
+   nil,    12,    72,    73,    74,    75,    70,    71,    67,    68,
+    65,    66,    69,    91,   nil,    59,    89,    29,    12,    30,
+   nil,    31,   nil,   nil,    32,    33,    27,    34,    35,    29,
+   nil,    30,    25,    31,   nil,   nil,    32,    33,    81,    34,
+    35,    16,   nil,    17,    25,    18,   nil,   nil,    19,    20,
+    77,    21,    22,    16,   nil,    17,   nil,    18,   nil,   nil,
+    19,    20,    42,    21,    22,    16,   nil,    17,   nil,    18,
+   nil,   nil,    19,    20,    85,    21,    22,    95,   nil,   nil,
+    93,   nil,   nil,   nil,    94 ]
 
 racc_action_check = [
-     1,     2,     1,     9,     1,    72,     1,    76,     1,    20,
-    20,    76,     1,     1,     1,    42,    42,     1,     8,     9,
-    11,    72,    32,    32,    32,    32,    32,    32,    32,    32,
-    32,    32,    32,    32,    12,    13,    32,    33,    33,    33,
-    33,    33,    33,    33,    33,    33,    33,    33,    33,    14,
-    15,    33,    34,    34,    34,    34,    34,    34,    34,    34,
-    34,    34,    34,    34,    16,    19,    34,    35,    35,    35,
-    35,    35,    35,    35,    35,    35,    35,    35,    35,    30,
-    40,    35,    36,    36,    36,    36,    36,    36,    36,    36,
-    36,    36,    36,    36,   nil,   nil,    36,    37,    37,    37,
-    37,    37,    37,    37,    37,    37,    37,    37,    37,   nil,
-   nil,    37,    43,    43,    43,    43,    43,    43,    43,    43,
-    43,    43,    43,    43,   nil,   nil,    43,    45,    45,    45,
-    45,    45,    45,    45,    45,    45,    45,    45,    45,    45,
-   nil,    45,    80,    80,    80,    80,    80,    80,    80,    80,
-    80,    80,    80,    80,    80,     7,    80,     7,   nil,     7,
-   nil,     7,   nil,   nil,   nil,     7,     7,    41,     7,    41,
-   nil,    41,   nil,    41,   nil,   nil,   nil,    41,    41,   nil,
-    41 ]
+     1,    13,     1,    41,     1,    13,     1,    41,     2,     1,
+     1,     1,     1,     1,     1,     1,     1,    10,    11,     1,
+    11,    25,    11,    24,    24,    11,    11,    11,    11,    11,
+    26,    26,    57,    57,    38,    40,    11,    44,    44,    44,
+    44,    44,    44,    44,    44,    44,    44,    44,    50,   nil,
+    44,   nil,   nil,    44,    55,    55,    55,    55,    55,    55,
+    55,    55,    55,    55,    55,   nil,   nil,    55,   nil,   nil,
+    55,    58,    58,    58,    58,    58,    58,    58,    58,    58,
+    58,    58,    58,   nil,    58,    58,   nil,    58,    91,    91,
+    91,    91,    91,    91,    91,    91,    91,    91,    91,    91,
+   nil,    91,    91,   nil,    91,    94,    94,    94,    94,    94,
+    94,    94,    94,    94,    94,    94,    94,   nil,    94,    94,
+   nil,    94,    95,    95,    95,    95,    95,    95,    95,    95,
+    95,    95,    95,    95,   nil,    95,    95,     9,    95,     9,
+   nil,     9,   nil,   nil,     9,     9,     9,     9,     9,    51,
+   nil,    51,     9,    51,   nil,   nil,    51,    51,    51,    51,
+    51,    45,   nil,    45,    51,    45,   nil,   nil,    45,    45,
+    45,    45,    45,    54,   nil,    54,   nil,    54,   nil,   nil,
+    54,    54,    54,    54,    54,    56,   nil,    56,   nil,    56,
+   nil,   nil,    56,    56,    56,    56,    56,    90,   nil,   nil,
+    90,   nil,   nil,   nil,    90 ]
 
 racc_action_pointer = [
-   nil,     0,     1,   nil,   nil,   nil,   nil,   153,     4,     1,
-   nil,     0,    14,    15,    29,    30,    44,   nil,   nil,    50,
-    -6,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-    59,   nil,    19,    34,    49,    64,    79,    94,   nil,   nil,
-    65,   165,    -3,   109,   nil,   124,   nil,   nil,   nil,   nil,
+   nil,     0,     8,   nil,   nil,   nil,   nil,   nil,   nil,   135,
+     1,    16,   nil,   -17,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,     9,     4,    13,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    14,   nil,
+    14,   -15,   nil,   nil,    34,   159,   nil,   nil,   nil,   nil,
+    31,   147,   nil,   nil,   171,    51,   183,    18,    68,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,     3,   nil,   nil,   nil,    -8,   nil,   nil,   nil,
-   139,   nil ]
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   183,    85,   nil,   nil,   102,   119,   nil,   nil,   nil ]
 
 racc_action_default = [
-    -1,   -58,   -58,    -2,    -3,    -4,    -5,   -58,    -8,   -58,
-   -22,   -58,   -58,   -58,   -58,   -58,   -58,    82,    -6,   -10,
-   -58,   -15,   -16,   -17,   -18,   -19,   -20,    -7,   -21,   -23,
-   -58,   -27,   -46,   -46,   -46,   -46,   -46,   -46,    -9,   -11,
-   -13,   -58,   -58,   -46,   -29,   -46,   -40,   -41,   -42,   -43,
-   -44,   -45,   -47,   -48,   -49,   -50,   -51,   -52,   -53,   -54,
-   -55,   -56,   -57,   -30,   -31,   -32,   -33,   -34,   -12,   -14,
-   -24,   -25,   -58,   -28,   -35,   -36,   -58,   -26,   -37,   -38,
-   -46,   -39 ]
+    -1,   -79,   -79,    -2,    -3,    -4,    -5,    -6,    -7,   -79,
+   -11,   -79,   -31,   -79,   -45,   -46,   -47,   -48,   -49,   -50,
+   -51,   -52,   -53,    99,   -79,   -13,   -79,   -20,   -21,   -22,
+   -23,   -24,   -25,   -26,   -27,   -28,   -10,   -29,   -79,   -32,
+   -33,   -79,   -39,   -40,   -67,   -79,    -8,    -9,   -12,   -14,
+   -16,   -79,   -30,   -34,   -79,   -67,   -79,   -79,   -67,   -61,
+   -62,   -63,   -64,   -65,   -66,   -68,   -69,   -70,   -71,   -72,
+   -73,   -74,   -75,   -76,   -77,   -78,   -43,   -44,   -15,   -17,
+   -18,   -19,   -35,   -36,   -37,   -38,   -41,   -42,   -54,   -55,
+   -79,   -67,   -56,   -58,   -67,   -67,   -57,   -59,   -60 ]
 
 racc_goto_table = [
-    28,    74,     1,    18,    44,    63,    64,    65,    66,    67,
-     3,     4,     5,     6,     7,    73,    39,    42,    70,    78,
-   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,    81,    69,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    15,    24,    38,    88,    28,    37,    57,     1,     3,     5,
+     6,     7,     9,    49,    53,    13,    92,    83,   nil,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,    77 ]
+   nil,   nil,    52,   nil,   nil,   nil,    96,   nil,   nil,    97,
+    98,   nil,   nil,    79,    76,    82,    80,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    84 ]
 
 racc_goto_check = [
-    11,    18,     1,     7,    15,    15,    15,    15,    15,    15,
-     2,     3,     4,     5,     6,    15,     9,    13,    14,    19,
-   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,    18,     7,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    18,     7,    13,    22,    10,    12,    17,     1,     2,     3,
+     4,     5,     6,     9,    15,    19,    23,    17,   nil,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,    11 ]
+   nil,   nil,    12,   nil,   nil,   nil,    22,   nil,   nil,    22,
+    22,   nil,   nil,     7,    18,    13,    10,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    18 ]
 
 racc_goto_pointer = [
-   nil,     2,     9,    10,    11,    12,    13,    -4,   nil,    -4,
-   nil,    -9,   nil,   -13,   -24,   -28,   nil,   nil,   -44,   -57,
-   nil,   nil,   nil ]
+   nil,     7,     7,     8,     9,    10,    11,    -8,   nil,   -13,
+    -5,   nil,    -6,    -9,   nil,   -26,   nil,   -38,    -1,    14,
+   nil,   nil,   -55,   -74,   nil,   nil,   nil ]
 
 racc_goto_default = [
-   nil,   nil,   nil,   nil,   nil,    49,   nil,   nil,    20,   nil,
-     9,   nil,    30,   nil,   nil,    76,    48,    45,   nil,   nil,
-    47,    50,    51 ]
+   nil,   nil,   nil,   nil,   nil,    62,   nil,   nil,    26,   nil,
+   nil,    11,   nil,   nil,    40,   nil,    41,    90,    43,   nil,
+    61,    58,   nil,   nil,    60,    63,    64 ]
 
 racc_reduce_table = [
   0, 0, :racc_error,
-  0, 22, :_reduce_none,
-  2, 22, :_reduce_none,
-  1, 23, :_reduce_none,
-  1, 23, :_reduce_none,
-  1, 23, :_reduce_none,
+  0, 24, :_reduce_none,
   2, 24, :_reduce_none,
-  2, 27, :_reduce_7,
-  1, 27, :_reduce_8,
-  2, 28, :_reduce_9,
-  1, 28, :_reduce_10,
-  2, 28, :_reduce_none,
+  2, 24, :_reduce_none,
+  1, 25, :_reduce_none,
+  1, 25, :_reduce_none,
+  1, 25, :_reduce_none,
+  1, 25, :_reduce_none,
+  3, 26, :_reduce_none,
+  3, 26, :_reduce_none,
+  2, 29, :_reduce_10,
+  1, 29, :_reduce_11,
   2, 30, :_reduce_12,
   1, 30, :_reduce_13,
   2, 30, :_reduce_none,
-  1, 29, :_reduce_15,
-  1, 29, :_reduce_16,
-  1, 29, :_reduce_17,
-  1, 29, :_reduce_18,
-  1, 29, :_reduce_19,
-  1, 29, :_reduce_20,
-  2, 26, :_reduce_none,
-  1, 31, :_reduce_22,
-  1, 32, :_reduce_23,
-  3, 32, :_reduce_none,
-  1, 35, :_reduce_25,
-  2, 35, :_reduce_none,
-  1, 33, :_reduce_27,
-  2, 34, :_reduce_none,
-  3, 25, :_reduce_29,
-  3, 25, :_reduce_30,
-  3, 25, :_reduce_31,
-  3, 25, :_reduce_32,
-  3, 25, :_reduce_33,
-  3, 25, :_reduce_34,
-  2, 37, :_reduce_none,
-  1, 39, :_reduce_36,
-  2, 39, :_reduce_none,
-  1, 40, :_reduce_38,
-  2, 40, :_reduce_none,
-  1, 38, :_reduce_40,
-  1, 36, :_reduce_41,
-  1, 36, :_reduce_none,
+  2, 32, :_reduce_15,
+  1, 32, :_reduce_16,
+  2, 32, :_reduce_none,
+  3, 31, :_reduce_18,
+  3, 31, :_reduce_19,
+  1, 31, :_reduce_20,
+  1, 31, :_reduce_21,
+  1, 33, :_reduce_none,
+  1, 33, :_reduce_23,
+  1, 33, :_reduce_none,
+  1, 33, :_reduce_none,
+  1, 33, :_reduce_none,
+  1, 33, :_reduce_none,
+  1, 33, :_reduce_none,
+  2, 28, :_reduce_none,
+  3, 28, :_reduce_none,
+  1, 34, :_reduce_31,
+  1, 35, :_reduce_32,
   1, 36, :_reduce_none,
+  2, 36, :_reduce_none,
+  2, 38, :_reduce_none,
+  3, 37, :_reduce_36,
+  3, 39, :_reduce_37,
+  3, 39, :_reduce_38,
+  1, 39, :_reduce_39,
+  1, 39, :_reduce_40,
+  4, 27, :_reduce_41,
+  4, 27, :_reduce_42,
+  3, 42, :_reduce_43,
+  3, 42, :_reduce_44,
+  1, 42, :_reduce_45,
+  1, 42, :_reduce_46,
   1, 41, :_reduce_none,
+  1, 41, :_reduce_48,
   1, 41, :_reduce_none,
-  0, 43, :_reduce_none,
-  1, 43, :_reduce_47,
-  1, 43, :_reduce_48,
-  1, 43, :_reduce_49,
-  1, 43, :_reduce_50,
-  1, 43, :_reduce_51,
-  1, 43, :_reduce_52,
-  1, 43, :_reduce_53,
-  1, 42, :_reduce_54,
-  1, 42, :_reduce_55,
-  1, 42, :_reduce_56,
-  1, 42, :_reduce_57 ]
-
-racc_reduce_n = 58
-
-racc_shift_n = 82
+  1, 41, :_reduce_none,
+  1, 41, :_reduce_none,
+  1, 41, :_reduce_none,
+  1, 41, :_reduce_none,
+  2, 43, :_reduce_none,
+  1, 45, :_reduce_55,
+  2, 45, :_reduce_none,
+  2, 45, :_reduce_none,
+  1, 46, :_reduce_58,
+  2, 46, :_reduce_none,
+  2, 46, :_reduce_none,
+  1, 44, :_reduce_61,
+  1, 40, :_reduce_62,
+  1, 40, :_reduce_none,
+  1, 40, :_reduce_none,
+  1, 47, :_reduce_none,
+  1, 47, :_reduce_none,
+  0, 49, :_reduce_none,
+  1, 49, :_reduce_68,
+  1, 49, :_reduce_69,
+  1, 49, :_reduce_70,
+  1, 49, :_reduce_71,
+  1, 49, :_reduce_72,
+  1, 49, :_reduce_73,
+  1, 49, :_reduce_74,
+  1, 48, :_reduce_75,
+  1, 48, :_reduce_76,
+  1, 48, :_reduce_77,
+  1, 48, :_reduce_78 ]
+
+racc_reduce_n = 79
+
+racc_shift_n = 99
 
 racc_token_table = {
   false => 0,
@@ -174,21 +199,23 @@ racc_token_table = {
   :STRING_LITERAL_MULTI => 5,
   :STRING_LITERAL => 6,
   :DATETIME => 7,
-  :INTEGER => 8,
-  :FLOAT => 9,
-  :FLOAT_INF => 10,
-  :FLOAT_NAN => 11,
-  :TRUE => 12,
-  :FALSE => 13,
-  "[" => 14,
-  "]" => 15,
-  "." => 16,
-  "{" => 17,
-  "}" => 18,
-  "," => 19,
-  "=" => 20 }
-
-racc_nt_base = 21
+  :LOCAL_TIME => 8,
+  :INTEGER => 9,
+  :NON_DEC_INTEGER => 10,
+  :FLOAT => 11,
+  :FLOAT_KEYWORD => 12,
+  :BOOLEAN => 13,
+  :NEWLINE => 14,
+  :EOS => 15,
+  "[" => 16,
+  "]" => 17,
+  "." => 18,
+  "{" => 19,
+  "}" => 20,
+  "," => 21,
+  "=" => 22 }
+
+racc_nt_base = 23
 
 racc_use_result_var = true
 
@@ -217,12 +244,14 @@ Racc_token_to_s_table = [
   "STRING_LITERAL_MULTI",
   "STRING_LITERAL",
   "DATETIME",
+  "LOCAL_TIME",
   "INTEGER",
+  "NON_DEC_INTEGER",
   "FLOAT",
-  "FLOAT_INF",
-  "FLOAT_NAN",
-  "TRUE",
-  "FALSE",
+  "FLOAT_KEYWORD",
+  "BOOLEAN",
+  "NEWLINE",
+  "EOS",
   "\"[\"",
   "\"]\"",
   "\".\"",
@@ -240,12 +269,16 @@ Racc_token_to_s_table = [
   "table_continued",
   "table_identifier",
   "table_next",
+  "table_identifier_component",
   "inline_table_start",
+  "inline_table_end",
   "inline_continued",
-  "inline_assignment_key",
-  "inline_assignment_value",
+  "inline_assignment",
   "inline_next",
+  "inline_assignment_key",
   "value",
+  "assignment_key_component",
+  "assignment_key",
   "array",
   "start_array",
   "array_continued",
@@ -272,291 +305,398 @@ Racc_debug_parser = false
 
 # reduce 6 omitted
 
-module_eval(<<'.,.,', 'parser.y', 15)
-  def _reduce_7(val, _values, result)
+# reduce 7 omitted
+
+# reduce 8 omitted
+
+# reduce 9 omitted
+
+module_eval(<<'.,.,', 'parser.y', 18)
+  def _reduce_10(val, _values, result)
      @handler.start_(:array_of_tables)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 16)
-  def _reduce_8(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 19)
+  def _reduce_11(val, _values, result)
      @handler.start_(:table)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 19)
-  def _reduce_9(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 22)
+  def _reduce_12(val, _values, result)
      array = @handler.end_(:array_of_tables); @handler.set_context(array, is_array_of_tables: true)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 20)
-  def _reduce_10(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 23)
+  def _reduce_13(val, _values, result)
      array = @handler.end_(:table); @handler.set_context(array)
     result
   end
 .,.,
 
-# reduce 11 omitted
+# reduce 14 omitted
 
-module_eval(<<'.,.,', 'parser.y', 24)
-  def _reduce_12(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 27)
+  def _reduce_15(val, _values, result)
      array = @handler.end_(:array_of_tables); @handler.set_context(array, is_array_of_tables: true)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 25)
-  def _reduce_13(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 28)
+  def _reduce_16(val, _values, result)
      array = @handler.end_(:table); @handler.set_context(array)
     result
   end
 .,.,
 
-# reduce 14 omitted
+# reduce 17 omitted
 
-module_eval(<<'.,.,', 'parser.y', 29)
-  def _reduce_15(val, _values, result)
-     @handler.push(val[0])
+module_eval(<<'.,.,', 'parser.y', 32)
+  def _reduce_18(val, _values, result)
+     @handler.push(val[2])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 30)
-  def _reduce_16(val, _values, result)
-     @handler.push(val[0])
+module_eval(<<'.,.,', 'parser.y', 33)
+  def _reduce_19(val, _values, result)
+     val[2].split('.').each { |k| @handler.push(k) }
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 31)
-  def _reduce_17(val, _values, result)
-     @handler.push(val[0])
+module_eval(<<'.,.,', 'parser.y', 35)
+  def _reduce_20(val, _values, result)
+          keys = val[0].split('.')
+      @handler.start_(:table)
+      keys.each { |key| @handler.push(key) }
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 32)
-  def _reduce_18(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 39)
+  def _reduce_21(val, _values, result)
      @handler.push(val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 33)
-  def _reduce_19(val, _values, result)
-     @handler.push(val[0])
+# reduce 22 omitted
+
+module_eval(<<'.,.,', 'parser.y', 43)
+  def _reduce_23(val, _values, result)
+     result = StringUtils.replace_escaped_chars(val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 34)
-  def _reduce_20(val, _values, result)
-     @handler.push(val[0])
+# reduce 24 omitted
+
+# reduce 25 omitted
+
+# reduce 26 omitted
+
+# reduce 27 omitted
+
+# reduce 28 omitted
+
+# reduce 29 omitted
+
+# reduce 30 omitted
+
+module_eval(<<'.,.,', 'parser.y', 55)
+  def _reduce_31(val, _values, result)
+     @handler.start_(:inline)
     result
   end
 .,.,
 
-# reduce 21 omitted
+module_eval(<<'.,.,', 'parser.y', 59)
+  def _reduce_32(val, _values, result)
+          array = @handler.end_(:inline)
+      @handler.push_inline(array)
 
-module_eval(<<'.,.,', 'parser.y', 40)
-  def _reduce_22(val, _values, result)
-     @handler.start_(:inline)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 43)
-  def _reduce_23(val, _values, result)
-     array = @handler.end_(:inline); @handler.push(Hash[*array])
+# reduce 33 omitted
+
+# reduce 34 omitted
+
+# reduce 35 omitted
+
+module_eval(<<'.,.,', 'parser.y', 72)
+  def _reduce_36(val, _values, result)
+          keys = @handler.end_(:inline_keys)
+      @handler.push(keys)
+
     result
   end
 .,.,
 
-# reduce 24 omitted
+module_eval(<<'.,.,', 'parser.y', 78)
+  def _reduce_37(val, _values, result)
+          @handler.push(val[2]) 
 
-module_eval(<<'.,.,', 'parser.y', 48)
-  def _reduce_25(val, _values, result)
-          array = @handler.end_(:inline)
-      array.map!.with_index{ |n,i| i.even? ? n.to_sym : n } if @handler.symbolize_keys
-      @handler.push(Hash[*array])
+    result
+  end
+.,.,
 
+module_eval(<<'.,.,', 'parser.y', 80)
+  def _reduce_38(val, _values, result)
+     val[2].split('.').each { |k| @handler.push(k) }
     result
   end
 .,.,
 
-# reduce 26 omitted
+module_eval(<<'.,.,', 'parser.y', 82)
+  def _reduce_39(val, _values, result)
+          keys = val[0].split('.')
+      @handler.start_(:inline_keys)
+      keys.each { |key| @handler.push(key) }
 
-module_eval(<<'.,.,', 'parser.y', 55)
-  def _reduce_27(val, _values, result)
-     @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 28 omitted
+module_eval(<<'.,.,', 'parser.y', 87)
+  def _reduce_40(val, _values, result)
+          @handler.start_(:inline_keys) 
+      @handler.push(val[0]) 
 
-module_eval(<<'.,.,', 'parser.y', 61)
-  def _reduce_29(val, _values, result)
-     @handler.assign(val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 62)
-  def _reduce_30(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 93)
+  def _reduce_41(val, _values, result)
+          keys = @handler.end_(:keys)
+      value = keys.pop
+      @handler.validate_value(value)
+      @handler.push(value)
+      @handler.assign(keys)
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 63)
-  def _reduce_31(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 100)
+  def _reduce_42(val, _values, result)
+          keys = @handler.end_(:keys)
+      value = keys.pop
+      @handler.validate_value(value)
+      @handler.push(value)
+      @handler.assign(keys)
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 64)
-  def _reduce_32(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 108)
+  def _reduce_43(val, _values, result)
+     @handler.push(val[2])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 65)
-  def _reduce_33(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 109)
+  def _reduce_44(val, _values, result)
+     val[2].split('.').each { |k| @handler.push(k) }
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 66)
-  def _reduce_34(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 111)
+  def _reduce_45(val, _values, result)
+          keys = val[0].split('.')
+      @handler.start_(:keys)
+      keys.each { |key| @handler.push(key) }
+
     result
   end
 .,.,
 
-# reduce 35 omitted
+module_eval(<<'.,.,', 'parser.y', 115)
+  def _reduce_46(val, _values, result)
+     @handler.start_(:keys); @handler.push(val[0])
+    result
+  end
+.,.,
 
-module_eval(<<'.,.,', 'parser.y', 72)
-  def _reduce_36(val, _values, result)
-     array = @handler.end_(:array); @handler.push(array)
+# reduce 47 omitted
+
+module_eval(<<'.,.,', 'parser.y', 119)
+  def _reduce_48(val, _values, result)
+     result = StringUtils.replace_escaped_chars(val[0])
     result
   end
 .,.,
 
-# reduce 37 omitted
+# reduce 49 omitted
 
-module_eval(<<'.,.,', 'parser.y', 76)
-  def _reduce_38(val, _values, result)
-     array = @handler.end_(:array); @handler.push(array)
+# reduce 50 omitted
+
+# reduce 51 omitted
+
+# reduce 52 omitted
+
+# reduce 53 omitted
+
+# reduce 54 omitted
+
+module_eval(<<'.,.,', 'parser.y', 130)
+  def _reduce_55(val, _values, result)
+     array = @handler.end_(:array); @handler.push(array.compact)
     result
   end
 .,.,
 
-# reduce 39 omitted
+# reduce 56 omitted
 
-module_eval(<<'.,.,', 'parser.y', 80)
-  def _reduce_40(val, _values, result)
+# reduce 57 omitted
+
+module_eval(<<'.,.,', 'parser.y', 135)
+  def _reduce_58(val, _values, result)
+     array = @handler.end_(:array); @handler.push(array.compact)
+    result
+  end
+.,.,
+
+# reduce 59 omitted
+
+# reduce 60 omitted
+
+module_eval(<<'.,.,', 'parser.y', 140)
+  def _reduce_61(val, _values, result)
      @handler.start_(:array)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 83)
-  def _reduce_41(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 143)
+  def _reduce_62(val, _values, result)
      @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 42 omitted
+# reduce 63 omitted
 
-# reduce 43 omitted
+# reduce 64 omitted
 
-# reduce 44 omitted
+# reduce 65 omitted
 
-# reduce 45 omitted
+# reduce 66 omitted
 
-# reduce 46 omitted
+# reduce 67 omitted
 
-module_eval(<<'.,.,', 'parser.y', 92)
-  def _reduce_47(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 152)
+  def _reduce_68(val, _values, result)
      result = val[0].to_f
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 93)
-  def _reduce_48(val, _values, result)
-     result = (val[0][0] == '-' ? -1 : 1) * Float::INFINITY
+module_eval(<<'.,.,', 'parser.y', 154)
+  def _reduce_69(val, _values, result)
+          v = val[0]
+      result = if v.end_with?('nan')
+                 Float::NAN
+               else
+                 (v[0] == '-' ? -1 : 1) * Float::INFINITY
+               end
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 94)
-  def _reduce_49(val, _values, result)
-     result = Float::NAN
+module_eval(<<'.,.,', 'parser.y', 161)
+  def _reduce_70(val, _values, result)
+     result = val[0].to_i
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 95)
-  def _reduce_50(val, _values, result)
-     result = val[0].to_i
+module_eval(<<'.,.,', 'parser.y', 163)
+  def _reduce_71(val, _values, result)
+          base = case val[0][1]
+             when "x" then 16
+             when "o" then 8
+             when "b" then 2
+             end
+      result = val[0].to_i(base)
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 96)
-  def _reduce_51(val, _values, result)
-     result = true
+module_eval(<<'.,.,', 'parser.y', 170)
+  def _reduce_72(val, _values, result)
+     result = val[0] == 'true' ? true : false
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 97)
-  def _reduce_52(val, _values, result)
-     result = false
+module_eval(<<'.,.,', 'parser.y', 172)
+  def _reduce_73(val, _values, result)
+          v = val[0]
+      result = if v[6].nil?
+                 if v[4].nil?
+                   LocalDate.new(v[0], v[1], v[2])
+                 else
+                   LocalDateTime.new(v[0], v[1], v[2], v[3] || 0, v[4] || 0, v[5].to_f)
+                 end
+               else
+                 # Patch for 24:00:00 which Ruby parses
+                 if v[3].to_i == 24 && v[4].to_i == 0 && v[5].to_i == 0
+                   v[3] = (v[3].to_i + 1).to_s
+                 end
+
+                 Time.new(v[0], v[1], v[2], v[3] || 0, v[4] || 0, v[5].to_f, v[6])
+               end
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 98)
-  def _reduce_53(val, _values, result)
-     result = Time.new(*val[0])
+module_eval(<<'.,.,', 'parser.y', 188)
+  def _reduce_74(val, _values, result)
+     result = LocalTime.new(*val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 101)
-  def _reduce_54(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 191)
+  def _reduce_75(val, _values, result)
      result = StringUtils.replace_escaped_chars(StringUtils.multiline_replacements(val[0]))
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 102)
-  def _reduce_55(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 192)
+  def _reduce_76(val, _values, result)
      result = StringUtils.replace_escaped_chars(val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 103)
-  def _reduce_56(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 193)
+  def _reduce_77(val, _values, result)
      result = StringUtils.strip_spaces(val[0])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 104)
-  def _reduce_57(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 194)
+  def _reduce_78(val, _values, result)
      result = val[0]
     result
   end
diff --git a/lib/tomlrb/handler.rb b/lib/tomlrb/handler.rb
index b9ba997..eb528d2 100644
--- a/lib/tomlrb/handler.rb
+++ b/lib/tomlrb/handler.rb
@@ -7,17 +7,24 @@ module Tomlrb
       @current = @output
       @stack = []
       @array_names = []
+      @current_table = []
+      @keys = Keys.new
       @symbolize_keys = options[:symbolize_keys]
     end
 
     def set_context(identifiers, is_array_of_tables: false)
+      if identifiers.empty?
+        raise ParseError, 'Array needs a name'
+      end
+
+      @current_table = identifiers.dup
+      @keys.add_table_key identifiers, is_array_of_tables
       @current = @output
 
       deal_with_array_of_tables(identifiers, is_array_of_tables) do |identifierz|
         identifierz.each do |k|
           k = k.to_sym if @symbolize_keys
           if @current[k].is_a?(Array)
-            @current[k] << {} if @current[k].empty?
             @current = @current[k].last
           else
             @current[k] ||= {}
@@ -28,7 +35,6 @@ module Tomlrb
     end
 
     def deal_with_array_of_tables(identifiers, is_array_of_tables)
-      identifiers.map!{|n| n.gsub("\"", '')}
       stringified_identifier = identifiers.join('.')
 
       if is_array_of_tables
@@ -43,20 +49,51 @@ module Tomlrb
       if is_array_of_tables
         last_identifier = last_identifier.to_sym if @symbolize_keys
         @current[last_identifier] ||= []
+        raise ParseError, "Cannot use key #{last_identifier} for both table and array at once" unless @current[last_identifier].respond_to?(:<<)
         @current[last_identifier] << {}
         @current = @current[last_identifier].last
       end
     end
 
     def assign(k)
-      k = k.to_sym if @symbolize_keys
-      @current[k] = @stack.pop
+      @keys.add_pair_key k, @current_table
+      current = @current
+      while key = k.shift
+        key = key.to_sym if @symbolize_keys
+        current = assign_key_path(current, key, k.empty?)
+      end
     end
 
     def push(o)
       @stack << o
     end
 
+    def push_inline(inline_arrays)
+      merged_inline = {}
+
+      inline_arrays.each do |inline_array|
+        current = merged_inline
+        value = inline_array.pop
+        inline_array.each_with_index do |inline_key, inline_index|
+          inline_key = inline_key.to_sym if @symbolize_keys
+          last_key = inline_index == inline_array.size - 1
+
+          if last_key
+            if current[inline_key].nil?
+              current[inline_key] = value
+            else
+              raise Key::KeyConflict, "Inline key #{inline_key} is already used"
+            end
+          else
+            current[inline_key] ||= {}
+            current = current[inline_key]
+          end
+        end
+      end
+
+      push(merged_inline)
+    end
+
     def start_(type)
       push([type])
     end
@@ -64,10 +101,166 @@ module Tomlrb
     def end_(type)
       array = []
       while (value = @stack.pop) != [type]
-        raise ParseError, 'Unclosed table' if value.nil?
+        raise ParseError, 'Unclosed table' if @stack.empty?
         array.unshift(value)
       end
       array
     end
+
+    def validate_value(value)
+      if value.nil?
+        raise ParseError, 'Value must be present'
+      end
+    end
+
+    private
+
+    def assign_key_path(current, key, key_emptied)
+      if key_emptied
+
+        raise ParseError, "Cannot overwrite value with key #{key}" unless current.kind_of?(Hash)
+        current[key] = @stack.pop
+        return current
+      end
+      current[key] ||= {}
+      current = current[key]
+      current
+    end
+  end
+
+  class Keys
+    def initialize
+      @keys = {}
+    end
+
+    def add_table_key(keys, is_array_of_tables = false)
+      self << [keys, [], is_array_of_tables]
+    end
+
+    def add_pair_key(keys, context)
+      self << [context, keys, false]
+    end
+
+    def <<(keys)
+      table_keys, pair_keys, is_array_of_tables = keys
+      current = @keys
+      current = append_table_keys(current, table_keys, pair_keys.empty?, is_array_of_tables)
+      append_pair_keys(current, pair_keys, table_keys.empty?, is_array_of_tables)
+    end
+
+    private
+
+    def append_table_keys(current, table_keys, pair_keys_empty, is_array_of_tables)
+      table_keys.each_with_index do |key, index|
+        declared = (index == table_keys.length - 1) && pair_keys_empty
+        if index == 0
+          current = find_or_create_first_table_key(current, key, declared, is_array_of_tables)
+        else
+          current = current << [key, :table, declared, is_array_of_tables]
+        end
+      end
+
+      current.clear_children if is_array_of_tables
+      current
+    end
+
+    def find_or_create_first_table_key(current, key, declared, is_array_of_tables)
+      existed = current[key]
+      if existed && existed.type == :pair
+        raise Key::KeyConflict, "Key #{key} is already used as #{existed.type} key"
+      end
+      if existed && existed.declared? && declared && ! is_array_of_tables
+        raise Key::KeyConflict, "Key #{key} is already used"
+      end
+      k = existed || Key.new(key, :table, declared)
+      current[key] = k
+      k
+    end
+
+    def append_pair_keys(current, pair_keys, table_keys_empty, is_array_of_tables)
+      pair_keys.each_with_index do |key, index|
+        declared = index == pair_keys.length - 1
+        if index == 0 && table_keys_empty
+          current = find_or_create_first_pair_key(current, key, declared, table_keys_empty)
+        else
+          key = current << [key, :pair, declared, is_array_of_tables]
+          current = key
+        end
+      end
+    end
+
+    def find_or_create_first_pair_key(current, key, declared, table_keys_empty)
+      existed = current[key]
+      if existed && (existed.type == :pair) && declared && table_keys_empty
+        raise Key::KeyConflict, "Key #{key} is already used"
+      end
+      k = Key.new(key, :pair, declared)
+      current[key] = k
+      k
+    end
+  end
+
+  class Key
+    class KeyConflict < ParseError; end
+
+    attr_reader :key, :type
+
+    def initialize(key, type, declared = false)
+      @key = key
+      @type = type
+      @declared = declared
+      @children = {}
+    end
+
+    def declared?
+      @declared
+    end
+
+    def <<(key_type_declared)
+      key, type, declared, is_array_of_tables = key_type_declared
+      existed = @children[key]
+      validate_already_declared_as_different_key(type, declared, existed)
+      validate_already_declared_as_non_array_table(type, is_array_of_tables, declared, existed)
+      validate_path_already_created_as_different_type(type, declared, existed)
+      validate_path_already_declared_as_different_type(type, declared, existed)
+      validate_already_declared_as_same_key(declared, existed)
+      @children[key] = existed || self.class.new(key, type, declared)
+    end
+
+    def clear_children
+      @children.clear
+    end
+
+    private
+
+    def validate_already_declared_as_different_key(type, declared, existed)
+      if existed && existed.declared? && existed.type != type
+        raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
+      end
+    end
+
+    def validate_already_declared_as_non_array_table(type, is_array_of_tables, declared, existed)
+      if declared && type == :table && existed && existed.declared? && ! is_array_of_tables
+        raise KeyConflict, "Key #{existed.key} is already used"
+      end
+    end
+
+    def validate_path_already_created_as_different_type(type, declared, existed)
+      if declared && (type == :table) && existed && (existed.type == :pair) && (! existed.declared?)
+        raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
+      end
+    end
+
+    def validate_path_already_declared_as_different_type(type, declared, existed)
+      if ! declared && (type == :pair) && existed && (existed.type == :pair) && existed.declared?
+        raise KeyConflict, "Key #{key} is already used as #{type} key"
+      end
+    end
+
+    def validate_already_declared_as_same_key(declared, existed)
+      if existed && ! existed.declared? && declared
+        raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
+      end
+    end
   end
 end
diff --git a/lib/tomlrb/local_date.rb b/lib/tomlrb/local_date.rb
new file mode 100644
index 0000000..7d99209
--- /dev/null
+++ b/lib/tomlrb/local_date.rb
@@ -0,0 +1,33 @@
+require 'forwardable'
+
+module Tomlrb
+  class LocalDate
+    extend Forwardable
+
+    def_delegators :@time, :year, :month, :day
+
+    def initialize(year, month, day)
+      @time = Time.new(year, month, day, 0, 0, 0, '-00:00')
+    end
+
+    # @param offset see {LocalDateTime#to_time}
+    # @return [Time] 00:00:00 of the date
+    def to_time(offset='-00:00')
+      return @time if offset == '-00:00'
+      Time.new(year, month, day, 0, 0, 0, offset)
+    end
+
+    def to_s
+      @time.strftime('%F')
+    end
+
+    def ==(other)
+      other.kind_of?(self.class) &&
+        to_time == other.to_time
+    end
+
+    def inspect
+      "#<#{self.class}: #{to_s}>"
+    end
+  end
+end
diff --git a/lib/tomlrb/local_date_time.rb b/lib/tomlrb/local_date_time.rb
new file mode 100644
index 0000000..18bf28c
--- /dev/null
+++ b/lib/tomlrb/local_date_time.rb
@@ -0,0 +1,40 @@
+require 'forwardable'
+
+module Tomlrb
+  class LocalDateTime
+    extend Forwardable
+
+    def_delegators :@time, :year, :month, :day, :hour, :min, :sec, :usec, :nsec
+
+    def initialize(year, month, day, hour, min, sec) # rubocop:disable Metrics/ParameterLists
+      @time = Time.new(year, month, day, hour, min, sec, '-00:00')
+      @sec = sec
+    end
+
+    # @param offset [String, Symbol, Numeric, nil] time zone offset.
+    #   * when +String+, must be '+HH:MM' format, '-HH:MM' format, 'UTC', 'A'..'I' or 'K'..'Z'. Arguments excluding '+-HH:MM' are supporeted at Ruby >= 2.7.0
+    #   * when +Symbol+, must be +:dst+(for summar time for local) or +:std+(for standard time).
+    #   * when +Numeric+, it is time zone offset in second.
+    #   * when +nil+, local time zone offset is used.
+    # @return [Time]
+    def to_time(offset='-00:00')
+      return @time if offset == '-00:00'
+      Time.new(year, month, day, hour, min, @sec, offset)
+    end
+
+    def to_s
+      frac = (@sec - sec)
+      frac_str = frac == 0 ? '' : "#{frac.to_s[1..-1]}"
+      @time.strftime("%FT%T") << frac_str
+    end
+
+    def ==(other)
+      other.kind_of?(self.class) &&
+        to_time == other.to_time
+    end
+
+    def inspect
+      "#<#{self.class}: #{to_s}>"
+    end
+  end
+end
diff --git a/lib/tomlrb/local_time.rb b/lib/tomlrb/local_time.rb
new file mode 100644
index 0000000..833ab5a
--- /dev/null
+++ b/lib/tomlrb/local_time.rb
@@ -0,0 +1,38 @@
+require 'forwardable'
+
+module Tomlrb
+  class LocalTime
+    extend Forwardable
+
+    def_delegators :@time, :hour, :min, :sec, :usec, :nsec
+
+    def initialize(hour, min, sec)
+      @time = Time.new(0, 1, 1, hour, min, sec, '-00:00')
+      @sec = sec
+    end
+
+    # @param year [Integer]
+    # @param month [Integer]
+    # @param day [Integer]
+    # @param offset see {LocalDateTime#to_time}
+    # @return [Time] the time of the date specified by params
+    def to_time(year, month, day, offset='-00:00')
+      Time.new(year, month, day, hour, min, @sec, offset)
+    end
+
+    def to_s
+      frac = (@sec - sec)
+      frac_str = frac == 0 ? '' : "#{frac.to_s[1..-1]}"
+      @time.strftime("%T") << frac_str
+    end
+
+    def ==(other)
+      other.kind_of?(self.class) &&
+        @time == other.to_time(0, 1, 1)
+    end
+
+    def inspect
+      "#<#{self.class}: #{to_s}>"
+    end
+  end
+end
diff --git a/lib/tomlrb/parser.y b/lib/tomlrb/parser.y
index ab712e7..8160bb6 100644
--- a/lib/tomlrb/parser.y
+++ b/lib/tomlrb/parser.y
@@ -1,16 +1,19 @@
 class Tomlrb::GeneratedParser
-token IDENTIFIER STRING_MULTI STRING_BASIC STRING_LITERAL_MULTI STRING_LITERAL DATETIME INTEGER FLOAT FLOAT_INF FLOAT_NAN TRUE FALSE
+token IDENTIFIER STRING_MULTI STRING_BASIC STRING_LITERAL_MULTI STRING_LITERAL DATETIME LOCAL_TIME INTEGER NON_DEC_INTEGER FLOAT FLOAT_KEYWORD BOOLEAN NEWLINE EOS
 rule
   expressions
     | expressions expression
+    | expressions EOS
     ;
   expression
     : table
     | assignment
     | inline_table
+    | NEWLINE
     ;
   table
-    : table_start table_continued
+    : table_start table_continued NEWLINE
+    | table_start table_continued EOS
     ;
   table_start
     : '[' '[' { @handler.start_(:array_of_tables) }
@@ -27,55 +30,112 @@ rule
     | '.' table_continued
     ;
   table_identifier
-    : IDENTIFIER { @handler.push(val[0]) }
-    | STRING_BASIC { @handler.push(val[0]) }
-    | STRING_LITERAL { @handler.push(val[0]) }
-    | INTEGER { @handler.push(val[0]) }
-    | TRUE { @handler.push(val[0]) }
-    | FALSE { @handler.push(val[0]) }
+    : table_identifier '.' table_identifier_component { @handler.push(val[2]) }
+    | table_identifier '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
+    | FLOAT {
+      keys = val[0].split('.')
+      @handler.start_(:table)
+      keys.each { |key| @handler.push(key) }
+    }
+    | table_identifier_component { @handler.push(val[0]) }
+    ;
+  table_identifier_component
+    : IDENTIFIER
+    | STRING_BASIC { result = StringUtils.replace_escaped_chars(val[0]) }
+    | STRING_LITERAL
+    | INTEGER
+    | NON_DEC_INTEGER
+    | FLOAT_KEYWORD
+    | BOOLEAN
     ;
   inline_table
-    : inline_table_start inline_continued
+    : inline_table_start inline_table_end
+    | inline_table_start inline_continued inline_table_end
     ;
   inline_table_start
     : '{' { @handler.start_(:inline) }
     ;
+  inline_table_end
+    : '}' {
+      array = @handler.end_(:inline)
+      @handler.push_inline(array)
+    }
+    ;
   inline_continued
-    : '}' { array = @handler.end_(:inline); @handler.push(Hash[*array]) }
-    | inline_assignment_key inline_assignment_value inline_next
+    : inline_assignment
+    | inline_assignment inline_next
     ;
   inline_next
-    : '}' {
-      array = @handler.end_(:inline)
-      array.map!.with_index{ |n,i| i.even? ? n.to_sym : n } if @handler.symbolize_keys
-      @handler.push(Hash[*array])
+    : ',' inline_continued
+    ;
+  inline_assignment
+    : inline_assignment_key '=' value {
+      keys = @handler.end_(:inline_keys)
+      @handler.push(keys)
     }
-    | ',' inline_continued
     ;
   inline_assignment_key
-    : IDENTIFIER { @handler.push(val[0]) }
-    ;
-  inline_assignment_value
-    : '=' value
+    : inline_assignment_key '.' assignment_key_component { 
+      @handler.push(val[2]) 
+    }
+    | inline_assignment_key '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
+    | FLOAT {
+      keys = val[0].split('.')
+      @handler.start_(:inline_keys)
+      keys.each { |key| @handler.push(key) }
+    }
+    | assignment_key_component { 
+      @handler.start_(:inline_keys) 
+      @handler.push(val[0]) 
+    }
     ;
   assignment
-    : IDENTIFIER '=' value { @handler.assign(val[0]) }
-    | STRING_BASIC '=' value { @handler.assign(val[0]) }
-    | STRING_LITERAL '=' value { @handler.assign(val[0]) }
-    | INTEGER '=' value { @handler.assign(val[0]) }
-    | TRUE '=' value { @handler.assign(val[0]) }
-    | FALSE '=' value { @handler.assign(val[0]) }
+    : assignment_key '=' value EOS {
+      keys = @handler.end_(:keys)
+      value = keys.pop
+      @handler.validate_value(value)
+      @handler.push(value)
+      @handler.assign(keys)
+    }
+    | assignment_key '=' value NEWLINE {
+      keys = @handler.end_(:keys)
+      value = keys.pop
+      @handler.validate_value(value)
+      @handler.push(value)
+      @handler.assign(keys)
+    }
+    ;
+  assignment_key
+    : assignment_key '.' assignment_key_component { @handler.push(val[2]) }
+    | assignment_key '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
+    | FLOAT {
+      keys = val[0].split('.')
+      @handler.start_(:keys)
+      keys.each { |key| @handler.push(key) }
+    }
+    | assignment_key_component { @handler.start_(:keys); @handler.push(val[0]) }
+    ;
+  assignment_key_component
+    : IDENTIFIER
+    | STRING_BASIC { result = StringUtils.replace_escaped_chars(val[0]) }
+    | STRING_LITERAL
+    | INTEGER
+    | NON_DEC_INTEGER
+    | FLOAT_KEYWORD
+    | BOOLEAN
     ;
   array
     : start_array array_continued
     ;
   array_continued
-    : ']' { array = @handler.end_(:array); @handler.push(array) }
+    : ']' { array = @handler.end_(:array); @handler.push(array.compact) }
     | value array_next
+    | NEWLINE array_continued
     ;
   array_next
-    : ']' { array = @handler.end_(:array); @handler.push(array) }
+    : ']' { array = @handler.end_(:array); @handler.push(array.compact) }
     | ',' array_continued
+    | NEWLINE array_continued
     ;
   start_array
     : '[' { @handler.start_(:array) }
@@ -91,12 +151,42 @@ rule
     ;
   literal
     | FLOAT { result = val[0].to_f }
-    | FLOAT_INF { result = (val[0][0] == '-' ? -1 : 1) * Float::INFINITY }
-    | FLOAT_NAN { result = Float::NAN }
+    | FLOAT_KEYWORD {
+      v = val[0]
+      result = if v.end_with?('nan')
+                 Float::NAN
+               else
+                 (v[0] == '-' ? -1 : 1) * Float::INFINITY
+               end
+    }
     | INTEGER { result = val[0].to_i }
-    | TRUE   { result = true }
-    | FALSE  { result = false }
-    | DATETIME { result = Time.new(*val[0])}
+    | NON_DEC_INTEGER {
+      base = case val[0][1]
+             when "x" then 16
+             when "o" then 8
+             when "b" then 2
+             end
+      result = val[0].to_i(base)
+    }
+    | BOOLEAN { result = val[0] == 'true' ? true : false }
+    | DATETIME {
+      v = val[0]
+      result = if v[6].nil?
+                 if v[4].nil?
+                   LocalDate.new(v[0], v[1], v[2])
+                 else
+                   LocalDateTime.new(v[0], v[1], v[2], v[3] || 0, v[4] || 0, v[5].to_f)
+                 end
+               else
+                 # Patch for 24:00:00 which Ruby parses
+                 if v[3].to_i == 24 && v[4].to_i == 0 && v[5].to_i == 0
+                   v[3] = (v[3].to_i + 1).to_s
+                 end
+
+                 Time.new(v[0], v[1], v[2], v[3] || 0, v[4] || 0, v[5].to_f, v[6])
+               end
+    }
+    | LOCAL_TIME { result = LocalTime.new(*val[0]) }
     ;
   string
     : STRING_MULTI { result = StringUtils.replace_escaped_chars(StringUtils.multiline_replacements(val[0])) }
diff --git a/lib/tomlrb/scanner.rb b/lib/tomlrb/scanner.rb
index 90f3fcb..f2c214b 100644
--- a/lib/tomlrb/scanner.rb
+++ b/lib/tomlrb/scanner.rb
@@ -2,57 +2,73 @@ require 'strscan'
 
 module Tomlrb
   class Scanner
-    COMMENT = /#.*/
+    COMMENT = /#[^\u0000-\u0008\u000A-\u001F\u007F]*/
     IDENTIFIER = /[A-Za-z0-9_-]+/
-    SPACE = /[ \t\r\n]/
-    STRING_BASIC = /(["])(?:\\?.)*?\1/
-    STRING_MULTI = /"{3}([\s\S]*?"{3,4})/m
-    STRING_LITERAL = /(['])(?:\\?.)*?\1/
-    STRING_LITERAL_MULTI = /'{3}([\s\S]*?'{3})/m
+    SPACE = /[ \t]/
+    NEWLINE = /(?:[ \t]*(?:\r?\n)[ \t]*)+/
+    STRING_BASIC = /(["])(?:\\?[^\u0000-\u0008\u000A-\u001F\u007F])*?\1/
+    STRING_MULTI = /"{3}([^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]*?(?<!\\)"{3,5})/m
+    STRING_LITERAL = /(['])(?:\\?[^\u0000-\u0008\u000A-\u001F\u007F])*?\1/
+    STRING_LITERAL_MULTI = /'{3}([^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]*?'{3,5})/m
     DATETIME = /(-?\d{4})-(\d{2})-(\d{2})(?:(?:t|\s)(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?))?(z|[-+]\d{2}:\d{2})?/i
-    FLOAT = /[+-]?(?:[0-9_]+\.[0-9_]*|\d+(?=[eE]))(?:[eE][+-]?[0-9_]+)?/
-    FLOAT_INF = /[+-]?inf/
-    FLOAT_NAN = /[+-]?nan/
+    LOCAL_TIME = /(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)/
+    FLOAT = /[+-]?(?:(?:\d|[1-9](?:_?\d)*)\.\d(?:_?\d)*|\d+(?=[eE]))(?:[eE][+-]?[0-9]+(_[0-9])*[0-9]*)?(?!\w)/
+    FLOAT_KEYWORD = /[+-]?(?:inf|nan)\b/
     INTEGER = /[+-]?([1-9](_?\d)*|0)(?![A-Za-z0-9_-]+)/
-    TRUE   = /true/
-    FALSE  = /false/
+    NON_DEC_INTEGER = /0(?:x[0-9A-Fa-f]+(?:_[0-9A-Fa-f])*[0-9A-Fa-f]*|o[0-7]+(?:_[0-7])*[0-7]*|b[01]+(?:_[01])*[01]*)/
+    BOOLEAN = /true|false/
+    SPACED_ARRAY_OF_TABLES_START = /^\[[ \t]+\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\]\]$/
+    SPACED_ARRAY_OF_TABLES_END = /^\[\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\][ \t]+\]$/
+    SPACED_ARRAY_OF_TABLES_BOTH = /^\[[ \t]+\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\][ \t]+\]$/
 
     def initialize(io)
       @ss = StringScanner.new(io.read)
+      @eos = false
     end
 
     def next_token
-      return if @ss.eos?
-
       case
+      when @ss.scan(NEWLINE) then [:NEWLINE, nil]
+      when @ss.scan(SPACED_ARRAY_OF_TABLES_START) then raise ParseError.new("Array of tables has spaces in starting brackets")
+      when @ss.scan(SPACED_ARRAY_OF_TABLES_END) then raise ParseError.new("Array of tables has spaces in ending brackets")
+      when @ss.scan(SPACED_ARRAY_OF_TABLES_BOTH) then raise ParseError.new("Array of tables has spaces in starting and ending brackets")
       when @ss.scan(SPACE) then next_token
       when @ss.scan(COMMENT) then next_token
       when @ss.scan(DATETIME) then process_datetime
+      when @ss.scan(LOCAL_TIME) then process_local_time
       when text = @ss.scan(STRING_MULTI) then [:STRING_MULTI, text[3..-4]]
       when text = @ss.scan(STRING_BASIC) then [:STRING_BASIC, text[1..-2]]
       when text = @ss.scan(STRING_LITERAL_MULTI) then [:STRING_LITERAL_MULTI, text[3..-4]]
       when text = @ss.scan(STRING_LITERAL) then [:STRING_LITERAL, text[1..-2]]
       when text = @ss.scan(FLOAT) then [:FLOAT, text]
-      when text = @ss.scan(FLOAT_INF) then [:FLOAT_INF, text]
-      when text = @ss.scan(FLOAT_NAN) then [:FLOAT_NAN, text]
+      when text = @ss.scan(FLOAT_KEYWORD) then [:FLOAT_KEYWORD, text]
       when text = @ss.scan(INTEGER) then [:INTEGER, text]
-      when text = @ss.scan(TRUE)   then [:TRUE, text]
-      when text = @ss.scan(FALSE)  then [:FALSE, text]
+      when text = @ss.scan(NON_DEC_INTEGER) then [:NON_DEC_INTEGER, text]
+      when text = @ss.scan(BOOLEAN) then [:BOOLEAN, text]
       when text = @ss.scan(IDENTIFIER) then [:IDENTIFIER, text]
-      else
-        x = @ss.getch
-        [x, x]
+      when @ss.eos? then process_eos
+      else x = @ss.getch; [x, x]
       end
     end
 
     def process_datetime
-      if @ss[7].nil?
-        offset = '+00:00'
-      else
-        offset = @ss[7].gsub('Z', '+00:00')
+      if @ss[7]
+        offset = @ss[7].gsub(/[zZ]/, '+00:00')
       end
-      args = [@ss[1], @ss[2], @ss[3], @ss[4] || 0, @ss[5] || 0, @ss[6].to_f, offset]
+      args = [@ss[1], @ss[2], @ss[3], @ss[4], @ss[5], @ss[6], offset]
       [:DATETIME, args]
     end
+
+    def process_local_time
+      args = [@ss[1], @ss[2], @ss[3].to_f]
+      [:LOCAL_TIME, args]
+    end
+
+    def process_eos
+      return if @eos
+
+      @eos = true
+      [:EOS, nil]
+    end
   end
 end
diff --git a/lib/tomlrb/string_utils.rb b/lib/tomlrb/string_utils.rb
index 53d27e4..139fb04 100644
--- a/lib/tomlrb/string_utils.rb
+++ b/lib/tomlrb/string_utils.rb
@@ -12,7 +12,13 @@ module Tomlrb
     }.freeze
 
     def self.multiline_replacements(str)
-      strip_spaces(str).gsub(/\\\n\s+/, '')
+      strip_spaces(str).gsub(/\\+\s*\n\s*/) {|matched|
+        if matched.match(/\\+/)[0].length.odd?
+          matched.gsub(/\\\s*\n\s*/, '')
+        else
+          matched
+        end
+      }
     end
 
     def self.replace_escaped_chars(str)
diff --git a/lib/tomlrb/version.rb b/lib/tomlrb/version.rb
index f8e1a44..b61120a 100644
--- a/lib/tomlrb/version.rb
+++ b/lib/tomlrb/version.rb
@@ -1,3 +1,3 @@
 module Tomlrb
-  VERSION = '1.3.0'.freeze
+  VERSION = '2.0.3'.freeze
 end
diff --git a/tomlrb.gemspec b/tomlrb.gemspec
index 18c476c..6d776c8 100644
--- a/tomlrb.gemspec
+++ b/tomlrb.gemspec
@@ -2,22 +2,32 @@
 # This file has been automatically generated by gem2tgz #
 #########################################################
 # -*- encoding: utf-8 -*-
-# stub: tomlrb 1.3.0 ruby lib
+# stub: tomlrb 2.0.3 ruby lib
 
 Gem::Specification.new do |s|
   s.name = "tomlrb".freeze
-  s.version = "1.3.0"
+  s.version = "2.0.3"
 
   s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
   s.require_paths = ["lib".freeze]
   s.authors = ["Francois Bernier".freeze]
-  s.date = "2020-03-19"
+  s.date = "2022-05-28"
   s.description = "A racc based toml parser".freeze
   s.email = ["frankbernier@gmail.com".freeze]
-  s.files = ["LICENSE.txt".freeze, "lib/tomlrb.rb".freeze, "lib/tomlrb/generated_parser.rb".freeze, "lib/tomlrb/handler.rb".freeze, "lib/tomlrb/parser.rb".freeze, "lib/tomlrb/parser.y".freeze, "lib/tomlrb/scanner.rb".freeze, "lib/tomlrb/string_utils.rb".freeze, "lib/tomlrb/version.rb".freeze]
+  s.files = ["LICENSE.txt".freeze, "lib/tomlrb.rb".freeze, "lib/tomlrb/generated_parser.rb".freeze, "lib/tomlrb/handler.rb".freeze, "lib/tomlrb/local_date.rb".freeze, "lib/tomlrb/local_date_time.rb".freeze, "lib/tomlrb/local_time.rb".freeze, "lib/tomlrb/parser.rb".freeze, "lib/tomlrb/parser.y".freeze, "lib/tomlrb/scanner.rb".freeze, "lib/tomlrb/string_utils.rb".freeze, "lib/tomlrb/version.rb".freeze]
   s.homepage = "https://github.com/fbernier/tomlrb".freeze
   s.licenses = ["MIT".freeze]
   s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
-  s.rubygems_version = "2.5.2.1".freeze
+  s.rubygems_version = "3.2.5".freeze
   s.summary = "A racc based toml parser".freeze
+
+  if s.respond_to? :specification_version then
+    s.specification_version = 4
+  end
+
+  if s.respond_to? :add_runtime_dependency then
+    s.add_development_dependency(%q<psych>.freeze, ["~> 4"])
+  else
+    s.add_dependency(%q<psych>.freeze, ["~> 4"])
+  end
 end

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/generated_parser.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/handler.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/local_date.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/local_date_time.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/local_time.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/parser.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/parser.y
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/scanner.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/string_utils.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-2.0.3/lib/tomlrb/version.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/tomlrb-2.0.3.gemspec

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/generated_parser.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/handler.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/parser.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/parser.y
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/scanner.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/string_utils.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/tomlrb-1.3.0/lib/tomlrb/version.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/tomlrb-1.3.0.gemspec

Control files: lines which differ (wdiff format)

  • Ruby-Versions: all

More details

Full run details