Skip to content

Commit

Permalink
add: basic type support
Browse files Browse the repository at this point in the history
  • Loading branch information
danini-the-panini committed Sep 21, 2021
1 parent ad2f622 commit 54eb406
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 17 deletions.
19 changes: 13 additions & 6 deletions lib/kdl/kdl.yy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class KDL::Parser
INTEGER FLOAT TRUE FALSE NULL
WS NEWLINE
LBRACE RBRACE
LPAREN RPAREN
EQUALS
SEMICOLON
EOF
Expand All @@ -22,6 +23,7 @@ rule
| node_decl node_children node_term { val[0].tap { |x| x.children = val[1] } }
| node_decl empty_children node_term { val[0].tap { |x| x.children = nil } }
node_decl : identifier { KDL::Node.new(val[0]) }
| type identifier { KDL::Node.new(val[1], type: val[0]) }
| node_decl WS value { val[0].tap { |x| x.arguments << val[2] } }
| node_decl WS SLASHDASH ws_star value { val[0] }
| node_decl WS property { val[0].tap { |x| x.properties[val[2][0]] = val[2][1] } }
Expand All @@ -34,18 +36,23 @@ rule
node_term: linespaces | semicolon_term
semicolon_term: SEMICOLON | SEMICOLON linespaces

type : LPAREN identifier RPAREN { val[1] }

identifier: IDENT { KDL::Key.new(val[0].value) }
| STRING { KDL::Key.new(val[0].value) }
| RAWSTRING { KDL::Key.new(val[0].value) }

property: identifier EQUALS value { [val[0], val[2]] }

value : STRING { KDL::Value::String.new(val[0].value) }
| RAWSTRING { KDL::Value::String.new(val[0].value) }
| INTEGER { KDL::Value::Int.new(val[0].value, format: val[0].meta[:format]) }
| FLOAT { KDL::Value::Float.new(val[0].value, format: val[0].meta[:format]) }
| boolean { KDL::Value::Boolean.new(val[0]) }
| NULL { KDL::Value::Null }
value : untyped_value
| type untyped_value { val[1].as_type(val[0]) }

untyped_value : STRING { KDL::Value::String.new(val[0].value) }
| RAWSTRING { KDL::Value::String.new(val[0].value) }
| INTEGER { KDL::Value::Int.new(val[0].value, format: val[0].meta[:format]) }
| FLOAT { KDL::Value::Float.new(val[0].value, format: val[0].meta[:format]) }
| boolean { KDL::Value::Boolean.new(val[0]) }
| NULL { KDL::Value::Null }

boolean : TRUE { true }
| FALSE { false }
Expand Down
7 changes: 4 additions & 3 deletions lib/kdl/node.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
module KDL
class Node
attr_accessor :name, :arguments, :properties, :children
attr_accessor :name, :arguments, :properties, :children, :type

def initialize(name, arguments = [], properties = {}, children = nil)
def initialize(name, arguments = [], properties = {}, children = nil, type: nil)
@name = name
@arguments = arguments
@properties = properties
@children = children
@type = type
end

def to_s(level = 0)
indent = ' ' * level
s = "#{indent}#{name}"
s = "#{indent}#{type ? "(#{type})" : ''}#{name}"
unless arguments.empty?
s += " #{arguments.map(&:to_s).join(' ')}"
end
Expand Down
2 changes: 2 additions & 0 deletions lib/kdl/tokenizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def to_s
SYMBOLS = {
'{' => :LBRACE,
'}' => :RBRACE,
'(' => :LPAREN,
')' => :RPAREN,
'=' => :EQUALS,
'=' => :EQUALS,
';' => :SEMICOLON
Expand Down
26 changes: 18 additions & 8 deletions lib/kdl/value.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
module KDL
class Value
attr_reader :value, :format
attr_reader :value, :format, :type

def initialize(value, format: nil)
def initialize(value, format: nil, type: nil)
@value = value
@format = format
@type = type
end

def as_type(type)
self.class.new(value, format: format, type: type)
end

def to_s
return stringify_value unless type

"(#{type})#{stringify_value}"
end

def stringify_value
return format % value if format

value.to_s
Expand All @@ -24,7 +35,7 @@ def ==(other)
other.is_a?(Float) && value == other.value
end

def to_s
def stringify_value
return super unless value.is_a?(BigDecimal)

sign, digits, _, exponent = value.split
Expand All @@ -42,7 +53,7 @@ def ==(other)
end

class String < Value
def to_s
def stringify_value
StringDumper.call(value)
end

Expand All @@ -52,14 +63,13 @@ def ==(other)
end

class NullImpl < Value
def initialize
super(nil)
def initialize(_=nil, format: nil, type: nil)
super(nil, type: type)
end

def to_s
def stringify_value
"null"
end
alias inspect to_s

def ==(other)
other.is_a?(NullImpl)
Expand Down
44 changes: 44 additions & 0 deletions test/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -452,4 +452,48 @@ def test_escaping
}
assert_equal nodes, doc
end

def test_node_type
doc = @parser.parse <<~KDL
(foo)node
KDL
nodes = ::KDL::Document.new([
::KDL::Node.new(::KDL::Key.new('node'), type: ::KDL::Key.new('foo')),
])
assert_equal nodes, doc
end

def test_value_type
doc = @parser.parse <<~KDL
node (foo)"bar"
KDL
nodes = ::KDL::Document.new([
::KDL::Node.new(::KDL::Key.new('node'), [::KDL::Value::String.new('bar', type: ::KDL::Key.new('foo'))]),
])
assert_equal nodes, doc
end

def test_property_type
doc = @parser.parse <<~KDL
node baz=(foo)"bar"
KDL
nodes = ::KDL::Document.new([
::KDL::Node.new(::KDL::Key.new('node'), [], { ::KDL::Key.new('baz') => ::KDL::Value::String.new('bar', type: ::KDL::Key.new('foo')) }),
])
assert_equal nodes, doc
end

def test_child_type
doc = @parser.parse <<~KDL
node {
(foo)bar
}
KDL
nodes = ::KDL::Document.new([
::KDL::Node.new(::KDL::Key.new('node'), [], {}, [
::KDL::Node.new(::KDL::Key.new('bar'), type: ::KDL::Key.new('foo'))
]),
])
assert_equal nodes, doc
end
end

0 comments on commit 54eb406

Please sign in to comment.