harfang3d/doc/doc_utils/metadata.py
2021-10-13 14:40:31 +02:00

132 lines
3.0 KiB
Python

from pypeg2 import *
# --
number = re.compile(r"-?([0-9]+\.([0-9]+)?f|\.[0-9]+(e[0-9]+)?f?|[0-9]+(e[0-9]+)?f?)")
string = re.compile(r"\"[^\"\\\r\n]*(?:\\.[^\"\\\r\n]*)*\"")
link = re.compile(r"\[(\w|\.)+\]")
# --Sample Text
class DirectiveParameter:
grammar = name(), optional("=", attr("value", [number, Literal, string, link]))
class DirectiveParameters(Namespace):
grammar = csl(DirectiveParameter)
# --
class DirectiveName(Plain):
grammar = contiguous('.', name())
class Directive(Plain):
"""Recursively parse a single or multi line directive declaration."""
@staticmethod
def parse(parser, text, pos):
o = Directive()
try:
text, name = parser.parse(text, DirectiveName)
except SyntaxError:
return text, parser.generate_syntax_error("expecting DirectiveName", pos)
setattr(o, 'name', name.name)
# short form directives .end is implicit
short_form_directives = ['img']
is_short_form = name.name in short_form_directives
# grab directive parameters
if text[:1] == '(':
eop = text.find(')')
if eop != -1:
try:
# multiple parameters
t, r = parser.parse(text[1:eop], DirectiveParameters)
setattr(o, 'parms', r)
text = text[eop+1:]
except SyntaxError:
# single string parameter
if text[1:2] == '"' and text[eop-1:eop] == '"':
setattr(o, 'parm', text[2:eop-1])
if is_short_form:
result = (text[eop+1:], o)
if not is_short_form:
# test for multi line directive
endmarker = ".end%s" % name.name
end = text.find(endmarker)
if end == -1:
end = text.find('\n')
if end == -1:
content = text # last single line directive
result = ('', o)
else:
content = text[:end] # single line directive
result = (text[end + 1:], o)
else:
content = text[:end] # multi line directive
result = (text[end + len(endmarker):], o)
# recursive directive content parse
t, content = parser.parse(content, MetaData)
setattr(o, 'content', content) # multi line directive
return result
class TextBlock(Plain):
@staticmethod
def parse(parser, text, pos):
if text == '':
return text, parser.generate_syntax_error("end of file!", pos)
o = TextBlock()
# accept anything until we hit something looking like a directive declaration
pos, end = 0, len(text)
while pos < end:
# skip to end of line
endl = text.find('\n', pos)
if endl != -1:
pos = endl + 1 # skip over the end of line
# test directive
try:
parser.parse(text[pos:], DirectiveName)
break # we hit a directive, end block here!
except SyntaxError:
pass # not a directive, proceed...
else:
pos = end
setattr(o, 'content', text[0:pos])
return text[pos:], o
def __str__(self):
return self.content
# --
class MetaData(List):
grammar = maybe_some([Directive, TextBlock])
metadata_parse_cache = {}
def parse_metadata(data):
if data in metadata_parse_cache:
return metadata_parse_cache[data]
output = parse(data, MetaData)
metadata_parse_cache[data] = output
return output