Page MenuHomec4science

libmultiscale_doc_parser.py
No OneTemporary

File Metadata

Created
Mon, Jun 3, 13:37

libmultiscale_doc_parser.py

#!/usr/bin/env python3
import pyparsing as pp
from attrdict import AttrDict
def test_parse(parser, to_test):
if __name__ != "__main__":
return
for _str in to_test:
try:
res = pp.Combine(parser).parseString(_str)
except pp.ParseException as e:
print('error while parsing: ', _str, '\n', e)
raise e
except pp.ParseSyntaxException as e:
print('error while parsing: ', _str, '\n', e)
raise e
print(res, _str)
if res[0] != _str.replace(" ", ""):
raise RuntimeError('error while parsing: ',
_str, res[0])
################################################################
# Grammar rules for C++ expressions
################################################################
_ref = pp.Literal('&')
_star = pp.Literal('*')
_plus = pp.Literal('+')
_div = pp.Literal('/')
_minus = pp.Literal('-')
ws = pp.White()
_operator = _star | _plus | _div | _minus
_float = pp.Combine(
pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?") + pp.Optional('u'))
_integer = _float
lpar = pp.Literal("(")
rpar = pp.Literal(")")
lcurl = pp.Literal("{")
rcurl = pp.Literal("}")
lsqr = pp.Literal("[")
rsqr = pp.Literal("]")
ltri = pp.Literal('<')
rtri = pp.Literal('>')
_l_brackets = lpar | lcurl | lsqr
_r_brackets = rpar | rcurl | rsqr
_this = pp.Literal('this->')
_var_name = pp.Word(pp.alphas, pp.alphanums + '_:')
_expr = pp.Forward()
_term = pp.Optional(_minus) + ((pp.Optional(_this) + _var_name) |
_float | pp.Group(lpar - _expr - rpar))
_expr << ((_term + pp.ZeroOrMore(_operator - _term)) |
(_star - _term) |
(_ref - _term) |
pp.QuotedString('"', unquoteResults=False) |
pp.QuotedString('\'', unquoteResults=False)
)
test_parse(_float, ["2", "2.", "2.2", "2E-3", "-2", "+2", "+2.e-3"])
test_parse(_expr, ["2", "-2*2", "2/4",
"toto", "toto*2", "std::toto",
"this->toto", "* toto", "& toto", '"toto"', 'dim * 2'])
################################################################
# Grammar rules for C++ types
################################################################
_template = pp.Forward()
_type = pp.Combine(_var_name + pp.Optional(_template))
_template <<= (
ltri -
pp.Optional((_type | _integer) + pp.Optional(_ref | _star)) +
pp.ZeroOrMore(pp.Literal(',') - (_type | pp.Word(pp.nums))) -
rtri)
test_parse(_type, [
'std::map<std::string, std::shared_ptr<py::object>>',
'int', 'vector<2>', 'list<double>', 'Vector<2u>'])
################################################################
# Grammar rules for C++ call
################################################################
_arguments = pp.Forward()
_constructor = _type + _l_brackets - _arguments - _r_brackets
_arg = pp.Combine(_constructor | _expr | _float)
_arguments <<= (
pp.Optional(_arg) + pp.ZeroOrMore(pp.Literal(',') - _arg))
test_parse(_constructor, [
'int()',
'std::map<std::string, std::shared_ptr<py::object>>{}',
'vector<2>()', 'list<double>(3,4)', 'Vector<2u>{2,4}'])
test_parse(_arguments, ['2', 'toto, 2', '2 * 2', 'dim * 2', '0u'])
_arguments_nocomma = (
pp.Optional(_arg) +
pp.ZeroOrMore(pp.Literal(',').suppress() +
pp.Optional(pp.White() | pp.LineEnd()).suppress() - _arg))
_call = pp.Literal('(') - _arguments - pp.Literal(')')
test_parse(_call, ['(2)', '(toto, 2)', '(2*2)', '(dim)', '(dim * 2)'])
################################################################
# Grammar rules libmultiscale
################################################################
etag = pp.Literal("*/")
tag_desc = pp.Literal("/* LMDESC")
tag_keyword = pp.Literal("/* LMKEYWORD")
tag_heritance = pp.Literal("/* LMHERITANCE")
tag_example = pp.Literal("/* LMEXAMPLE")
def block(tag):
_header = pp.SkipTo(tag) + tag
_content = pp.SkipTo(etag)
_block = _header.suppress() - _content
_block -= etag.suppress()
return _block
def named_block(tag):
_header = pp.SkipTo(tag) + tag
_header += pp.ZeroOrMore(pp.White())
_block = _header.suppress() - pp.Word(pp.alphanums+"_")
_block -= pp.OneOrMore(pp.White() | pp.LineEnd()).suppress()
_block -= pp.SkipTo(etag)
_block -= etag.suppress()
res = _block
return res
description = named_block(tag_desc)
example = block(tag_example)
heritance = block(tag_heritance)
################################################################
def setTag(tok, tag):
print(tok)
tok.tag = tag
return tok
parse_tag = (pp.Literal("this->parseTag").suppress() -
pp.Literal('(').suppress() - pp.QuotedString('"') +
_arguments_nocomma - pp.Literal(')').suppress())
parse_keyword = (pp.Literal("this->parseKeyword").suppress() -
pp.Literal('(').suppress() - pp.QuotedString('"') +
_arguments_nocomma - pp.Literal(')').suppress())
parse_veckeyword = (pp.Literal("this->parseVectorKeyword").suppress() -
pp.Literal('(').suppress() - pp.QuotedString('"') +
_arguments_nocomma - pp.Literal(')').suppress())
parse_declaration = (parse_tag | parse_keyword |
parse_veckeyword) + pp.Literal(';').suppress()
def check_declaration(toks):
return toks[0] == toks[2]
keyword = (named_block(tag_keyword) -
parse_declaration).addCondition(check_declaration,
message="Documentation != Code")
lm_content = pp.Group(description).setResultsName("description")
lm_content += pp.Group(pp.Optional(example)).setResultsName("example")
lm_content += pp.Group(pp.Optional(heritance)).setResultsName("heritance")
lm_content += pp.Group(pp.ZeroOrMore(pp.Group(keyword))
).setResultsName("keywords")
################################################################
# Grammar tests
################################################################
test_parse(_type, ['std::map<std::string, std::shared_ptr<py::object>>'])
test_parse(_arg, ['toto', 'std::toto', '"toto"', '2',
'-toto', '2.', '2.2', 'toto()', 'dim * 2',
'this->toto', 'toto<int>()', 'toto<3>()',
'toto<int, 2>()'
])
test_parse(_arguments, ['1., 2, "toto"',
'1., -2, -toto',
'1., 2, "toto", std::map<std::string, '
'std::shared_ptr<py::object>>(), toto()'])
test_parse(_call, ['(1., 2, "toto")',
'(1., 2, "toto", std::map<std::string, '
'std::shared_ptr<py::object>>(), toto())',
'(-2)', '(-toto)', '(1., -2, -toto)', '(dim * 2)',
'(1., dim * 2)'
])
res = description.parseString("""
/* LMDESC TIMEAVG
This computes a time averaged version of a set of reals
*/
""")
assert(res[0] == 'TIMEAVG')
assert(res[1] == 'This computes a time averaged version of a set of reals\n')
res = example.parseString("""
/* LMEXAMPLE
COMPUTE disp EXTRACT INPUT md FIELD displacement\\
COMPUTE time_average TIMEAVG INPUT disp\\
*/
""")
assert(res[0] == '''COMPUTE disp EXTRACT INPUT md FIELD displacement\\
COMPUTE time_average TIMEAVG INPUT disp\\
''')
res = heritance.parseString("""
/* LMHERITANCE action_interface*/
""")
assert(res[0] == 'action_interface')
res = keyword.parseString("""
/* LMKEYWORD PROC
Flag to request processor number to each DOF
*/
this->parseTag("PROC", proc_field, false);
""")
assert(res[0] == 'PROC')
assert(res[1].strip() == 'Flag to request processor number to each DOF')
assert(res[2] == 'PROC')
assert(res[3] == 'proc_field')
assert(res[4] == 'false')
res = keyword.parseString("""
/* LMKEYWORD BOUNDARY
flag to request output of nodal blockage
*/
this->parseKeyword("BOUNDARY", boundary_field, false);
""")
assert(res[0] == 'BOUNDARY')
assert(res[1].strip() == 'flag to request output of nodal blockage')
assert(res[2] == 'BOUNDARY')
assert(res[3] == 'boundary_field')
assert(res[4] == 'false')
res = keyword.parseString("""
/* LMKEYWORD DIR
Whether to block in x direction*/
this->parseVectorKeyword("DIR", Dim, this->block,
VEC_DEFAULTS(false, false, false));
""")
assert(res[0] == 'DIR')
assert(res[1].strip() == 'Whether to block in x direction')
assert(res[2] == 'DIR')
assert(res[3] == 'Dim')
assert(res[4] == 'this->block')
assert(res[5] == 'VEC_DEFAULTS(false,false,false)')
res = keyword.parseString("""
/* LMKEYWORD MAX
specify a maximum threshold
*/
this->parseKeyword("MAX", max, -lm_real_max);
""")
assert(res[0] == 'MAX')
assert(res[1].strip() == 'specify a maximum threshold')
assert(res[2] == 'MAX')
assert(res[3] == 'max')
assert(res[4] == '-lm_real_max')
res = keyword.parseString("""
/* LMKEYWORD PBC
Specify the pbc flags (one per direction) for neighbor detection
*/
this->parseVectorKeyword("PBC", spatial_dimension, pbc_flag,
VEC_DEFAULTS(false, false, false));
""")
assert(res[0] == 'PBC')
assert(res[1].strip() ==
'Specify the pbc flags (one per direction) for neighbor detection')
assert(res[2] == 'PBC')
assert(res[3] == 'spatial_dimension')
assert(res[4] == 'pbc_flag')
assert(res[5] == 'VEC_DEFAULTS(false,false,false)')
res = lm_content.parseString("""
/* LMDESC PYTHON
This computes an array of reals based on a python script
*/
/* LMEXAMPLE
COMPUTE disp EXTRACT INPUT md FIELD displacement \\\\
COMPUTE disp2 PYTHON INPUT disp FILENAME script \\\\
with a python script stored in a file script.py with the content such
as:\\\\
import numpy as np\\ \\
def compute(**kwargs):\\
~~vec = np.copy(kwargs["disp"])\\
~~vec *= 2. \\
~~return vec
*/
void ComputePython::declareParams() {
""")
try:
res = keyword.parseString("""
/* LMKEYWORD DIR
Whether to block in x direction*/
this->parseVectorKeyword("DIR2", Dim, this->block);
""")
raise RuntimeError("should not parse")
except pp.ParseException:
pass
################################################################
# Libmultiscale parser
################################################################
class LibMultiScaleParser:
def parse(self, filename, internal_key_list):
fin = open(filename, 'r')
inp = fin.read()
fin.close()
res = lm_content.parseString(inp)
return res.asDict()

Event Timeline