Added auto-construction, tidied h_ch a bit

This commit is contained in:
Dan Hirsch 2013-11-08 17:20:00 -05:00 committed by Meredith L. Patterson
parent a4dbfc61f2
commit a99d7a18d1

View file

@ -4,7 +4,8 @@ import sys
_ffi = FFI() _ffi = FFI()
## Types # {{{ Types
_ffi.cdef("typedef struct HAllocator_ HAllocator;") _ffi.cdef("typedef struct HAllocator_ HAllocator;")
_ffi.cdef("typedef struct HArena_ HArena;") _ffi.cdef("typedef struct HArena_ HArena;")
_ffi.cdef("typedef int bool;") _ffi.cdef("typedef int bool;")
@ -110,10 +111,12 @@ typedef struct HBenchmarkResults_ {
} HBenchmarkResults; } HBenchmarkResults;
""") """)
## Arena functions # }}}
# {{{ Arena functions
_ffi.cdef("void* h_arena_malloc(HArena *arena, size_t count);") _ffi.cdef("void* h_arena_malloc(HArena *arena, size_t count);")
_ffi.cdef("void h_arena_free(HArena *arena, void* ptr);") _ffi.cdef("void h_arena_free(HArena *arena, void* ptr);")
# }}}
# {{{ cdefs
## The following section was generated by ## The following section was generated by
## $ perl ../desugar-header.pl <../../hammer.h |sed -e 's/.*/_ffi.cdef("&")/' ## $ perl ../desugar-header.pl <../../hammer.h |sed -e 's/.*/_ffi.cdef("&")/'
_ffi.cdef("HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length);") _ffi.cdef("HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length);")
@ -216,7 +219,7 @@ _lib = _ffi.verify("#include <hammer/hammer.h>",
libraries=['hammer']) libraries=['hammer'])
_lib.TT_PYTHON = _lib.TT_USER # TODO: Use the token type allocator from #45 _lib.TT_PYTHON = _lib.TT_USER # TODO: Use the token type allocator from #45
# }}}
class _DynamicScopeHolder(threading.local): class _DynamicScopeHolder(threading.local):
"""A dynamically-scoped holder of python objects, which may or may not """A dynamically-scoped holder of python objects, which may or may not
otherwise appear in the object graph. Intended for use with CFFI """ otherwise appear in the object graph. Intended for use with CFFI """
@ -263,8 +266,8 @@ def _toHParsedToken(arena, pyobj):
hpt = _ffi.cast("HParsedToken*", _lib.h_arena_malloc(_ffi.sizeof(parseResult.arena, "HParsedToken"))) hpt = _ffi.cast("HParsedToken*", _lib.h_arena_malloc(_ffi.sizeof(parseResult.arena, "HParsedToken")))
hpt.token_type = _lib.TT_PYTHON hpt.token_type = _lib.TT_PYTHON
hpt.user = cobj hpt.user = cobj
hpt.bit_offset = 127; hpt.bit_offset = chr(127)
hpt.index = 0; hpt.index = 0
return hpt return hpt
def _fromParseResult(cobj): def _fromParseResult(cobj):
@ -311,6 +314,11 @@ class Parser(object):
else: else:
return None return None
def __mul__(self, count):
return repeat_n(self, count)
class IndirectParser(Parser): class IndirectParser(Parser):
def bind(self, inner): def bind(self, inner):
_lib.h_bind_indirect(self._parser, inner._parser) _lib.h_bind_indirect(self._parser, inner._parser)
@ -326,12 +334,20 @@ def token(token):
return Parser(_lib.h_token(token, len(token)), ()) return Parser(_lib.h_token(token, len(token)), ())
def ch(char): def ch(char):
return token(char) """Returns either a token or an int, depending on the type of the
argument"""
if isinstance(char, int):
return Parser(_lib.h_ch(char), ())
else:
return token(char)
def ch_range(chr1, chr2): def ch_range(chr1, chr2):
if not isinstance(chr1, str) or not isinstance(chr2, str): if not isinstance(chr1, str) or not isinstance(chr2, str):
raise TypeError("ch_range can't handle unicode") raise TypeError("ch_range can't handle unicode")
return Parser(_lib.h_ch_range(chr1, chr2), ()) def my_action(pr):
# print "In action: ", pr
return pr
return action(Parser(_lib.h_ch_range(ord(chr1), ord(chr2)), ()), my_action)
def int_range(parser, i1, i2): def int_range(parser, i1, i2):
if type(parser) != BitsParser: if type(parser) != BitsParser:
@ -436,3 +452,36 @@ def run_test():
ch('3')), ch('3')),
ch(',')) ch(','))
return p_test.parse("1,2,3") return p_test.parse("1,2,3")
# {{{ Automatic parser construction... python specific
# TODO: Implement Parsable metaclass, which requires the existence of
# a "parse" method.
# This is expected to be extended by user code. As a general rule,
# only provide auto-parsers for your own types.
AUTO_PARSERS = {
str: token,
unicode: token,
}
def _auto_seq(lst):
return sequence(*(auto_1(p, default_method=_auto_choice)
for p in lst))
def _auto_choice(lst):
return choice(*(auto_1(p, default_method=_auto_seq)
for p in lst))
def auto_1(arg, default_method=_auto_choice):
if isinstance(arg, Parser):
return arg
elif type(arg) in AUTO_PARSERS:
return AUTO_PARSERS[type(arg)](arg)
else:
return default_method(arg)
def auto(*args):
return auto_1(args, default_method=_auto_choice)
# }}}