Compare commits
3 Commits
91a1434b49
...
7d4b991f4a
Author | SHA1 | Date |
---|---|---|
|
7d4b991f4a | |
|
ed8a3ebcf4 | |
|
be69396f69 |
|
@ -8,7 +8,7 @@ nor does it enforce the 16-level cap on keys and blocks.
|
||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
`py-xbc` currently requires `pyparsing` and Python 3.3+.
|
`py-xbc` currently requires `pyparsing` and Python 3.7+.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import pytest
|
||||||
|
|
||||||
from xbc import loads_xbc, ParseError
|
from xbc import loads_xbc, ParseError
|
||||||
|
|
||||||
class TestBare:
|
class TestBareLoad:
|
||||||
def test_key(self):
|
def test_key(self):
|
||||||
assert loads_xbc('a') == {'a': True}
|
assert loads_xbc('a') == {'a': True}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class TestBare:
|
||||||
assert loads_xbc('a.a;a.b') == {'a.a': True, 'a.b': True}
|
assert loads_xbc('a.a;a.b') == {'a.a': True, 'a.b': True}
|
||||||
|
|
||||||
def test_string(self):
|
def test_string(self):
|
||||||
assert loads_xbc('a = "b"') == {'a': '"b"'}
|
assert loads_xbc('a = "b"') == {'a': 'b'}
|
||||||
|
|
||||||
def test_array(self):
|
def test_array(self):
|
||||||
assert loads_xbc('a = 1, 2') == {'a': ['1', '2']}
|
assert loads_xbc('a = 1, 2') == {'a': ['1', '2']}
|
||||||
|
@ -35,9 +35,6 @@ class TestBare:
|
||||||
with pytest.raises(ParseError):
|
with pytest.raises(ParseError):
|
||||||
loads_xbc('a = 1\na = 2')
|
loads_xbc('a = 1\na = 2')
|
||||||
|
|
||||||
# currently the lexer doesn't correctly parse keyvalues with semis
|
|
||||||
# outside of blocks. no idea why.
|
|
||||||
@pytest.mark.xfail
|
|
||||||
def test_reassignment_colon(self):
|
def test_reassignment_colon(self):
|
||||||
with pytest.raises(ParseError):
|
with pytest.raises(ParseError):
|
||||||
loads_xbc('a = 1;a = 2')
|
loads_xbc('a = 1;a = 2')
|
||||||
|
@ -46,7 +43,7 @@ class TestBare:
|
||||||
with pytest.raises(ParseError):
|
with pytest.raises(ParseError):
|
||||||
loads_xbc('a := 1')
|
loads_xbc('a := 1')
|
||||||
|
|
||||||
class TestBlock:
|
class TestBlockLoad:
|
||||||
def test_keyvalue(self):
|
def test_keyvalue(self):
|
||||||
assert loads_xbc('a { a = 1 }') == {'a': False, 'a.a': '1'}
|
assert loads_xbc('a { a = 1 }') == {'a': False, 'a.a': '1'}
|
||||||
|
|
||||||
|
|
|
@ -112,8 +112,8 @@ key_fragment = Word(alphas + nums + '_-')
|
||||||
key = DelimitedList(key_fragment, delim='.', combine=True)
|
key = DelimitedList(key_fragment, delim='.', combine=True)
|
||||||
|
|
||||||
bareval = CharsNotIn(' {}#=+:;,\n\'"')
|
bareval = CharsNotIn(' {}#=+:;,\n\'"')
|
||||||
strvals = QuotedString("'", multiline=True, unquote_results=False)
|
strvals = QuotedString("'", multiline=True, unquote_results=True)
|
||||||
strvald = QuotedString('"', multiline=True, unquote_results=False)
|
strvald = QuotedString('"', multiline=True, unquote_results=True)
|
||||||
value = bareval | strvald | strvals
|
value = bareval | strvald | strvals
|
||||||
|
|
||||||
assign = Literal('=')
|
assign = Literal('=')
|
||||||
|
@ -123,6 +123,7 @@ op = assign | update | append
|
||||||
semi = Literal(';').suppress()
|
semi = Literal(';').suppress()
|
||||||
lbrace = Literal('{').suppress()
|
lbrace = Literal('{').suppress()
|
||||||
rbrace = Literal('}').suppress()
|
rbrace = Literal('}').suppress()
|
||||||
|
terminal = Word(';\n').suppress()
|
||||||
|
|
||||||
NL = Literal('\n').suppress()
|
NL = Literal('\n').suppress()
|
||||||
WS = Word(' \t').suppress()
|
WS = Word(' \t').suppress()
|
||||||
|
@ -134,23 +135,18 @@ values = Group(value + ZeroOrMore(Literal(',').suppress() + Optional(WS_NL) + va
|
||||||
keyvalue = Group(key + Optional(WS) + op + Optional(WS) + values, aslist=True)
|
keyvalue = Group(key + Optional(WS) + op + Optional(WS) + values, aslist=True)
|
||||||
keyvalue.set_parse_action(lambda x: KeyValue(x))
|
keyvalue.set_parse_action(lambda x: KeyValue(x))
|
||||||
|
|
||||||
key_stmt = Optional(WS) + key + Optional(assign).suppress() + Optional(WS)
|
key_stmt = key + Optional(WS) + Optional(assign).suppress() + Optional(WS)
|
||||||
key_stmt.set_parse_action(lambda x: Key(x))
|
key_stmt.set_parse_action(lambda x: Key(x))
|
||||||
kv_stmt = Optional(WS) + keyvalue + Optional(WS)
|
|
||||||
|
|
||||||
block = Forward()
|
block = Forward()
|
||||||
statement = kv_stmt | key_stmt
|
statement = (keyvalue | key_stmt)
|
||||||
term_stmt = kv_stmt | key_stmt + Optional(semi) + Optional(WS)
|
statements = DelimitedList(statement, delim=terminal)
|
||||||
|
segment = Group(OneOrMore(block | statements), aslist=True)
|
||||||
|
|
||||||
line_statements = Group(term_stmt + ZeroOrMore(NL + term_stmt))
|
block << Group(key + Optional(WS) + lbrace + segment + rbrace + Optional(NL))
|
||||||
term_stmt_list = Group(statement + ZeroOrMore(semi + statement))
|
|
||||||
|
|
||||||
segment = OneOrMore(block | term_stmt_list | line_statements)
|
|
||||||
|
|
||||||
block << Group(key + Optional(WS) + lbrace + Group(segment, aslist=True) + rbrace + Optional(NL))
|
|
||||||
block.set_parse_action(lambda x: Block(x))
|
block.set_parse_action(lambda x: Block(x))
|
||||||
|
|
||||||
data = OneOrMore(block | (term_stmt + Optional(NL)))
|
data = OneOrMore(segment)
|
||||||
|
|
||||||
XBCParser = data
|
XBCParser = data
|
||||||
|
|
||||||
|
@ -214,6 +210,9 @@ def parse_block(key, seq):
|
||||||
if k not in ret:
|
if k not in ret:
|
||||||
ret[k] = False
|
ret[k] = False
|
||||||
|
|
||||||
|
if not isinstance(value, list):
|
||||||
|
value = [value]
|
||||||
|
|
||||||
ret.update(parse_block(k, value))
|
ret.update(parse_block(k, value))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
Loading…
Reference in New Issue