diff --git a/debian/changelog b/debian/changelog
index 7d6048d..ba7637c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-tomlrb (2.0.1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 22 May 2022 03:20:07 -0000
+
 ruby-tomlrb (1.3.0-2) unstable; urgency=medium
 
   [ Stefano Rivera ]
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..5d35204 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.5.1
+# from Racc grammar file "".
 #
 
 require 'racc/parser.rb'
@@ -10,160 +10,177 @@ 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,    43,    16,    41,    17,    42,    18,    44,    45,    19,
+    20,    14,    21,    22,     8,     4,    10,    48,    49,    12,
+    23,    39,    69,    70,    71,    72,    67,    68,    64,    65,
+    62,    63,    66,    52,    36,    56,    46,    53,    12,    69,
+    70,    71,    72,    67,    68,    64,    65,    62,    63,    66,
+    84,    83,    56,    39,    75,    12,    69,    70,    71,    72,
+    67,    68,    64,    65,    62,    63,    66,    88,    80,    56,
+    86,    81,    12,    69,    70,    71,    72,    67,    68,    64,
+    65,    62,    63,    66,    88,    41,    56,    86,   nil,    12,
+    69,    70,    71,    72,    67,    68,    64,    65,    62,    63,
+    66,    88,   nil,    56,    86,   nil,    12,    69,    70,    71,
+    72,    67,    68,    64,    65,    62,    63,    66,    88,   nil,
+    56,    86,    29,    12,    30,   nil,    31,   nil,   nil,    32,
+    33,    27,    34,    35,    29,   nil,    30,    25,    31,   nil,
+   nil,    32,    33,    78,    34,    35,    16,   nil,    17,    25,
+    18,   nil,   nil,    19,    20,    74,    21,    22,    93,   nil,
+   nil,    91,   nil,   nil,   nil,    92 ]
 
 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,    11,     1,    13,     1,    24,    24,     1,
+     1,     1,     1,     1,     1,     1,     1,    26,    26,     1,
+     2,    11,    42,    42,    42,    42,    42,    42,    42,    42,
+    42,    42,    42,    40,    10,    42,    25,    40,    42,    53,
+    53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
+    54,    54,    53,    38,    48,    53,    55,    55,    55,    55,
+    55,    55,    55,    55,    55,    55,    55,    55,    51,    55,
+    55,    52,    55,    88,    88,    88,    88,    88,    88,    88,
+    88,    88,    88,    88,    88,    80,    88,    88,   nil,    88,
+    92,    92,    92,    92,    92,    92,    92,    92,    92,    92,
+    92,    92,   nil,    92,    92,   nil,    92,    93,    93,    93,
+    93,    93,    93,    93,    93,    93,    93,    93,    93,   nil,
+    93,    93,     9,    93,     9,   nil,     9,   nil,   nil,     9,
+     9,     9,     9,     9,    49,   nil,    49,     9,    49,   nil,
+   nil,    49,    49,    49,    49,    49,    43,   nil,    43,    49,
+    43,   nil,   nil,    43,    43,    43,    43,    43,    87,   nil,
+   nil,    87,   nil,   nil,   nil,    87 ]
 
 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,    20,   nil,   nil,   nil,   nil,   nil,   nil,   120,
+    18,     1,   nil,   -17,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    -7,    19,     0,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    33,   nil,
+    15,   nil,    19,   144,   nil,   nil,   nil,   nil,    37,   132,
+   nil,    47,    69,    36,    36,    53,   nil,   nil,   nil,   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 ]
+    83,   nil,   nil,   nil,   nil,   nil,   nil,   144,    70,   nil,
+   nil,   nil,    87,   104,   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,   -77,   -77,    -2,    -3,    -4,    -5,    -6,    -7,   -77,
+   -11,   -77,   -31,   -77,   -43,   -44,   -45,   -46,   -47,   -48,
+   -49,   -50,   -51,    97,   -77,   -13,   -77,   -20,   -21,   -22,
+   -23,   -24,   -25,   -26,   -27,   -28,   -10,   -29,   -77,   -32,
+   -77,   -37,   -65,   -77,    -8,    -9,   -12,   -14,   -16,   -77,
+   -30,   -33,   -77,   -65,   -77,   -65,   -59,   -60,   -61,   -62,
+   -63,   -64,   -66,   -67,   -68,   -69,   -70,   -71,   -72,   -73,
+   -74,   -75,   -76,   -41,   -42,   -15,   -17,   -18,   -19,   -34,
+   -77,   -36,   -38,   -39,   -40,   -52,   -53,   -77,   -65,   -35,
+   -54,   -56,   -65,   -65,   -55,   -57,   -58 ]
 
 racc_goto_table = [
-    28,    74,     1,    18,    44,    63,    64,    65,    66,    67,
-     3,     4,     5,     6,     7,    73,    39,    42,    70,    78,
+    38,    15,    24,    85,    28,    37,    54,     1,     3,     5,
+     6,     7,     9,    47,    51,    79,    13,    82,    90,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,    81,    69,   nil,   nil,
+   nil,   nil,    50,   nil,   nil,   nil,    94,   nil,   nil,   nil,
+    95,    96,    76,    73,    77,   nil,   nil,   nil,   nil,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,    77 ]
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    89 ]
 
 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,
+    13,    19,     7,    22,    10,    12,    17,     1,     2,     3,
+     4,     5,     6,     9,    15,    16,    18,    17,    23,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,    12,   nil,   nil,   nil,    22,   nil,   nil,   nil,
+    22,    22,     7,    19,    10,   nil,   nil,   nil,   nil,   nil,
    nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
-   nil,   nil,   nil,    11 ]
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    13 ]
 
 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,    -7,   nil,   -13,
+    -5,   nil,    -6,   -11,   nil,   -26,   -36,   -36,    15,     0,
+   nil,   nil,   -52,   -69,   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,    59,   nil,   nil,    26,   nil,
+   nil,    11,   nil,   nil,    40,   nil,   nil,    87,   nil,   nil,
+    58,    55,   nil,   nil,    57,    60,    61 ]
 
 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, 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_none,
+  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,
+  2, 36, :_reduce_none,
+  3, 36, :_reduce_none,
   2, 39, :_reduce_none,
-  1, 40, :_reduce_38,
-  2, 40, :_reduce_none,
-  1, 38, :_reduce_40,
-  1, 36, :_reduce_41,
-  1, 36, :_reduce_none,
-  1, 36, :_reduce_none,
-  1, 41, :_reduce_none,
-  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
+  3, 37, :_reduce_36,
+  1, 37, :_reduce_37,
+  2, 38, :_reduce_none,
+  4, 27, :_reduce_39,
+  4, 27, :_reduce_40,
+  3, 41, :_reduce_41,
+  3, 41, :_reduce_42,
+  1, 41, :_reduce_43,
+  1, 41, :_reduce_44,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  1, 42, :_reduce_none,
+  2, 43, :_reduce_none,
+  1, 45, :_reduce_53,
+  2, 45, :_reduce_none,
+  2, 45, :_reduce_none,
+  1, 46, :_reduce_56,
+  2, 46, :_reduce_none,
+  2, 46, :_reduce_none,
+  1, 44, :_reduce_59,
+  1, 40, :_reduce_60,
+  1, 40, :_reduce_none,
+  1, 40, :_reduce_none,
+  1, 47, :_reduce_none,
+  1, 47, :_reduce_none,
+  0, 49, :_reduce_none,
+  1, 49, :_reduce_66,
+  1, 49, :_reduce_67,
+  1, 49, :_reduce_68,
+  1, 49, :_reduce_69,
+  1, 49, :_reduce_70,
+  1, 49, :_reduce_71,
+  1, 49, :_reduce_72,
+  1, 48, :_reduce_73,
+  1, 48, :_reduce_74,
+  1, 48, :_reduce_75,
+  1, 48, :_reduce_76 ]
+
+racc_reduce_n = 77
+
+racc_shift_n = 97
 
 racc_token_table = {
   false => 0,
@@ -174,21 +191,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 +236,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 +261,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_next",
   "value",
+  "assignment_key",
+  "assignment_key_component",
   "array",
   "start_array",
   "array_continued",
@@ -272,44 +297,34 @@ Racc_debug_parser = false
 
 # reduce 6 omitted
 
-module_eval(<<'.,.,', 'parser.y', 15)
-  def _reduce_7(val, _values, result)
-     @handler.start_(:array_of_tables)
-    result
-  end
-.,.,
+# reduce 7 omitted
 
-module_eval(<<'.,.,', 'parser.y', 16)
-  def _reduce_8(val, _values, result)
-     @handler.start_(:table)
-    result
-  end
-.,.,
+# reduce 8 omitted
 
-module_eval(<<'.,.,', 'parser.y', 19)
-  def _reduce_9(val, _values, result)
-     array = @handler.end_(:array_of_tables); @handler.set_context(array, is_array_of_tables: true)
+# 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', 20)
-  def _reduce_10(val, _values, result)
-     array = @handler.end_(:table); @handler.set_context(array)
+module_eval(<<'.,.,', 'parser.y', 19)
+  def _reduce_11(val, _values, result)
+     @handler.start_(:table)
     result
   end
 .,.,
 
-# reduce 11 omitted
-
-module_eval(<<'.,.,', 'parser.y', 24)
+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', 25)
+module_eval(<<'.,.,', 'parser.y', 23)
   def _reduce_13(val, _values, result)
      array = @handler.end_(:table); @handler.set_context(array)
     result
@@ -318,245 +333,321 @@ module_eval(<<'.,.,', 'parser.y', 25)
 
 # reduce 14 omitted
 
-module_eval(<<'.,.,', 'parser.y', 29)
+module_eval(<<'.,.,', 'parser.y', 27)
   def _reduce_15(val, _values, result)
-     @handler.push(val[0])
+     array = @handler.end_(:array_of_tables); @handler.set_context(array, is_array_of_tables: true)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 30)
+module_eval(<<'.,.,', 'parser.y', 28)
   def _reduce_16(val, _values, result)
-     @handler.push(val[0])
+     array = @handler.end_(:table); @handler.set_context(array)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 31)
-  def _reduce_17(val, _values, result)
-     @handler.push(val[0])
-    result
-  end
-.,.,
+# reduce 17 omitted
 
 module_eval(<<'.,.,', 'parser.y', 32)
   def _reduce_18(val, _values, result)
-     @handler.push(val[0])
+     @handler.push(val[2])
     result
   end
 .,.,
 
 module_eval(<<'.,.,', 'parser.y', 33)
   def _reduce_19(val, _values, result)
-     @handler.push(val[0])
+     val[2].split('.').each { |k| @handler.push(k) }
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 34)
+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', 39)
+  def _reduce_21(val, _values, result)
      @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 21 omitted
+# reduce 22 omitted
+
+# reduce 23 omitted
+
+# reduce 24 omitted
+
+# reduce 25 omitted
+
+# reduce 26 omitted
+
+# reduce 27 omitted
+
+# reduce 28 omitted
 
-module_eval(<<'.,.,', 'parser.y', 40)
-  def _reduce_22(val, _values, result)
+# reduce 29 omitted
+
+# reduce 30 omitted
+
+module_eval(<<'.,.,', 'parser.y', 55)
+  def _reduce_31(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])
+module_eval(<<'.,.,', 'parser.y', 59)
+  def _reduce_32(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
 .,.,
 
-# reduce 24 omitted
+# reduce 33 omitted
+
+# reduce 34 omitted
+
+# reduce 35 omitted
 
-module_eval(<<'.,.,', 'parser.y', 48)
-  def _reduce_25(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 73)
+  def _reduce_36(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])
+      array.each { |key| @handler.push(key) }
+      @handler.start_(:inline)
+      @handler.push(val[2])
 
     result
   end
 .,.,
 
-# reduce 26 omitted
-
-module_eval(<<'.,.,', 'parser.y', 55)
-  def _reduce_27(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 78)
+  def _reduce_37(val, _values, result)
      @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 28 omitted
+# reduce 38 omitted
+
+module_eval(<<'.,.,', 'parser.y', 85)
+  def _reduce_39(val, _values, result)
+          keys = @handler.end_(:keys)
+      @handler.push(keys.pop)
+      @handler.assign(keys)
 
-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', 90)
+  def _reduce_40(val, _values, result)
+          keys = @handler.end_(:keys)
+      @handler.push(keys.pop)
+      @handler.assign(keys)
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 63)
-  def _reduce_31(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 96)
+  def _reduce_41(val, _values, result)
+     @handler.push(val[2])
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 64)
-  def _reduce_32(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 97)
+  def _reduce_42(val, _values, result)
+     val[2].split('.').each { |k| @handler.push(k) }
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 65)
-  def _reduce_33(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 99)
+  def _reduce_43(val, _values, result)
+          keys = val[0].split('.')
+      @handler.start_(:keys)
+      keys.each { |key| @handler.push(key) }
+
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 66)
-  def _reduce_34(val, _values, result)
-     @handler.assign(val[0])
+module_eval(<<'.,.,', 'parser.y', 103)
+  def _reduce_44(val, _values, result)
+     @handler.start_(:keys); @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 35 omitted
+# reduce 45 omitted
 
-module_eval(<<'.,.,', 'parser.y', 72)
-  def _reduce_36(val, _values, result)
+# reduce 46 omitted
+
+# reduce 47 omitted
+
+# reduce 48 omitted
+
+# reduce 49 omitted
+
+# reduce 50 omitted
+
+# reduce 51 omitted
+
+# reduce 52 omitted
+
+module_eval(<<'.,.,', 'parser.y', 118)
+  def _reduce_53(val, _values, result)
      array = @handler.end_(:array); @handler.push(array)
     result
   end
 .,.,
 
-# reduce 37 omitted
+# reduce 54 omitted
+
+# reduce 55 omitted
 
-module_eval(<<'.,.,', 'parser.y', 76)
-  def _reduce_38(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 123)
+  def _reduce_56(val, _values, result)
      array = @handler.end_(:array); @handler.push(array)
     result
   end
 .,.,
 
-# reduce 39 omitted
+# reduce 57 omitted
 
-module_eval(<<'.,.,', 'parser.y', 80)
-  def _reduce_40(val, _values, result)
+# reduce 58 omitted
+
+module_eval(<<'.,.,', 'parser.y', 128)
+  def _reduce_59(val, _values, result)
      @handler.start_(:array)
     result
   end
 .,.,
 
-module_eval(<<'.,.,', 'parser.y', 83)
-  def _reduce_41(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 131)
+  def _reduce_60(val, _values, result)
      @handler.push(val[0])
     result
   end
 .,.,
 
-# reduce 42 omitted
+# reduce 61 omitted
 
-# reduce 43 omitted
+# reduce 62 omitted
 
-# reduce 44 omitted
+# reduce 63 omitted
 
-# reduce 45 omitted
+# reduce 64 omitted
 
-# reduce 46 omitted
+# reduce 65 omitted
 
-module_eval(<<'.,.,', 'parser.y', 92)
-  def _reduce_47(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 140)
+  def _reduce_66(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', 142)
+  def _reduce_67(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', 149)
+  def _reduce_68(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', 151)
+  def _reduce_69(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', 158)
+  def _reduce_70(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', 160)
+  def _reduce_71(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
+                 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', 171)
+  def _reduce_72(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', 174)
+  def _reduce_73(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', 175)
+  def _reduce_74(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', 176)
+  def _reduce_75(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', 177)
+  def _reduce_76(val, _values, result)
      result = val[0]
     result
   end
diff --git a/lib/tomlrb/handler.rb b/lib/tomlrb/handler.rb
index b9ba997..c1c7666 100644
--- a/lib/tomlrb/handler.rb
+++ b/lib/tomlrb/handler.rb
@@ -7,10 +7,14 @@ 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)
+      @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|
@@ -43,14 +47,19 @@ 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)
@@ -69,5 +78,154 @@ module Tomlrb
       end
       array
     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.declared? && (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 declared && 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..75825ce 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,44 +30,87 @@ 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
+    | 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_continued
-    : '}' { array = @handler.end_(:inline); @handler.push(Hash[*array]) }
-    | inline_assignment_key inline_assignment_value inline_next
-    ;
-  inline_next
+  inline_table_end
     : '}' {
       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_continued
+    : inline_assignment_key inline_assignment_value
+    | inline_assignment_key inline_assignment_value inline_next
+    ;
+  inline_next
+    : ',' inline_continued
     ;
   inline_assignment_key
-    : IDENTIFIER { @handler.push(val[0]) }
+    : inline_assignment_key '.' IDENTIFIER {
+      array = @handler.end_(:inline)
+      array.each { |key| @handler.push(key) }
+      @handler.start_(:inline)
+      @handler.push(val[2])
+    }
+    | IDENTIFIER { @handler.push(val[0]) }
     ;
   inline_assignment_value
     : '=' value
     ;
   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)
+      @handler.push(keys.pop)
+      @handler.assign(keys)
+    }
+    | assignment_key '=' value NEWLINE {
+      keys = @handler.end_(:keys)
+      @handler.push(keys.pop)
+      @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
+    | STRING_LITERAL
+    | INTEGER
+    | NON_DEC_INTEGER
+    | FLOAT_KEYWORD
+    | BOOLEAN
     ;
   array
     : start_array array_continued
@@ -72,10 +118,12 @@ rule
   array_continued
     : ']' { array = @handler.end_(:array); @handler.push(array) }
     | value array_next
+    | NEWLINE array_continued
     ;
   array_next
     : ']' { array = @handler.end_(:array); @handler.push(array) }
     | ',' array_continued
+    | NEWLINE array_continued
     ;
   start_array
     : '[' { @handler.start_(:array) }
@@ -91,12 +139,37 @@ 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
+                 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..386c04e 100644
--- a/lib/tomlrb/scanner.rb
+++ b/lib/tomlrb/scanner.rb
@@ -2,57 +2,67 @@ 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_]+)?(?!\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_]*|o[0-7][0-7_]*|b[01][01_]*)/
+    BOOLEAN = /true|false/
 
     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(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
+      if @ss[7]
         offset = @ss[7].gsub('Z', '+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..3b9b34d 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.1'.freeze
 end
diff --git a/tomlrb.gemspec b/tomlrb.gemspec
index 18c476c..0236159 100644
--- a/tomlrb.gemspec
+++ b/tomlrb.gemspec
@@ -2,19 +2,19 @@
 # This file has been automatically generated by gem2tgz #
 #########################################################
 # -*- encoding: utf-8 -*-
-# stub: tomlrb 1.3.0 ruby lib
+# stub: tomlrb 2.0.1 ruby lib
 
 Gem::Specification.new do |s|
   s.name = "tomlrb".freeze
-  s.version = "1.3.0"
+  s.version = "2.0.1"
 
   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 = "2020-12-20"
   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)