mirror of
https://github.com/harfang3d/harfang3d.git
synced 2024-06-16 12:03:04 +00:00
132 lines
3.0 KiB
Python
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
|