zayfod / pyfranca

A Python module and tools for working with Franca interface definition language (IDL) models.
MIT License
19 stars 13 forks source link

Exampel Header generator #9

Open jb090979 opened 7 years ago

jb090979 commented 7 years ago

The original franca project provide an example HppGenerator.

https://github.com/franca/franca/blob/master/examples/org.franca.examples.basic/src/org/franca/examples/basic/generators/ExampleHppGenerator.xtend

I think for all pyfranca users would it be usefull to have an example code generator.
What do you think about this idea?

I can create one if you like. My idea is to create a simple C++ header file using jinja2 as template library.

gunnarx commented 7 years ago

@jb090979 Please consider my experiments on code generation, build on top of it, or build your own stuff. It's jinja2 based.

Sorry I have not looked into this upstream repo in a while. (I had to fork to make some quick changes when I implemented it.) I hope in any case that we can together build some interest around various code generation tools based on this Franca parser (and jinja).

jb090979 commented 7 years ago

@gunnarx Thanks for cpp generator. Is a good start. My own generator is also based on jinja2 and similay to CommonAPI generator. But sorry I do not have permission to publish this code. But I also do a lot of changes on pyfranca. Sorry to say but zayfod currently has no time or lost the interest to go on with pyfranca. So all my changes are in my own fork:

https://github.com/jb090979/pyfranca/tree/dev_jb

This branch contains the following changes

So maybe you take a look on my branch. Without zayfod I can not push my changes upstream. But I would prever that we work on the same code base.

A few questions to you generator: What is the purpose of the CPP-Genrator? Just a simpel HP Generator like the Example Generator of franca https://github.com/franca/franca/tree/master/examples/org.franca.examples.basic/src/org/franca/examples/basic/generators. Or do you want a generator like CommonAPI?

gunnarx commented 7 years ago

A few questions to you generator:

Basically I realize there's a lot to do to make this to the CommonAPI level. It now just produces skeleton code, not really organized for proper use. (For one thing, a separate server and client code is not even being created. I guess it's basically a skeleton for a server at this point).

The extent to which I had the time to complete it, it was mostly done for two purposes:

  1. A way to just prove the concept what would be possible to do for code generation with pyfranca + jinja, hopefully also encouraging others to take it from there.

  2. A simple way to show a Franca API in HTML documentation pages. In this case what Doxygen produces of course has a distinct C/C++ flavor, since I run it over the generated code. Nonetheless, it was one way to create a cross-referenced and browsable API documentation of sorts.
    (I published the Doxygen result on the GitHub pages - did you see it?)

Thanks a lot for pointing out your fork - I'm not working actively on this at the moment but I will monitor it, and we can keep in touch on any improvements.

jb090979 commented 7 years ago

thats fine.

In particular for point 2 I add the structured comment support to pyfranca. So you are able to render the structured comments in the fidl file as Doxygen comment in cpp.

So in pyfranca class ast each member got a field "comments" this is an ordered dict with the franca metatags as keys and the corrsponding test as value. My render function looks like :

def render_comments(comments, tag, with_brief=False, with_comment_sign=False, with_intro=False, add_spaces=""): comment = "" # first line newline = "" # start of additional lines has_comment = False

newline += "\n" + add_spaces

if with_comment_sign:
    comment += "/** "
    newline += "    "
    comment += add_spaces
elif with_intro:
    comment += newline + "Specification from Fidl file:" + newline

if tag == "@description" or tag == "all":

    if "@description" in comments.keys():
        has_comment = True
        spaces = newline
        if with_brief:
            comment += "@brief "
            spaces += "       "

        tmp = comments['@description']
        tmp2 = tmp.split('\n')
        comment += tmp2[0].strip()  # first line

        # additional lines
        if len(tmp2) > 1:
            # there must be one spare line between brief and remaining text
            if with_brief:
                comment += "\n"

            for myStr in tmp2[1:]:
                comment += spaces + (myStr.strip())

if tag == "@author" or tag == "all":
    if "@author" in comments.keys():
        has_comment = True
        spaces = newline

        comment += "\n" + newline
        comment += "@author"
        spaces += "       "

        tmp = comments['@author']
        tmp2 = tmp.split('\n')
        comment += tmp2[0]  # first line

        # additional lines
        if len(tmp2) > 1:
            for myStr in tmp2[1:]:
                comment += spaces + (myStr.strip())

if tag == "@see" or tag == "all":
    if "@see" in comments.keys():
        has_comment = True
        spaces = newline
        comment += "\n" + newline
        comment += "@see "
        spaces += "     "

        tmp = comments['@see']
        tmp2 = tmp.split('\n')
        comment += tmp2[0]  # first line

        # additional lines
        if len(tmp2) > 1:
            for myStr in tmp2[1:]:
                comment += spaces + (myStr.strip())

if tag == "@deprecated" or tag == "all":
    if "@deprecated" in comments.keys():
        has_comment = True
        spaces = newline

        comment += "\n" + newline
        comment += "@deprecated "
        spaces += "            "

        tmp = comments['@deprecated']
        tmp2 = tmp.split('\n')
        comment += tmp2[0]  # first line

        # additional lines
        if len(tmp2) > 1:
            for myStr in tmp2[1:]:
                comment += spaces + (myStr.strip())

if with_comment_sign:
    comment += "  */"

# if ther is no comment, do not write any sign
if not has_comment:
    comment = ""

return comment
jb090979 commented 7 years ago

some advises:

your generator process one fidl file after another. I start the same way but if you consider the import directive it could be that you import multiple packages while processing one fidl file. An Example:

file1.fidl imports file2.fidl

you start your generator with pyfranca_cpp.py file1.fidl file2.fidl

Now you will process the packages in file2.fidl 2 times. It is may better to process all input files in pyfranca processor in a first step and in a second one render all packages. pyfrance has no problem to process packages twice. It detects that a package is already process and skip further processing. Anyway you use my fork. In zayfod latest version there is a bug. :-)

gunnarx commented 7 years ago

Yeah I knew I had an issue with includes, and other things. Thanks for the suggestions. My code is still messy, and the limitations are also not well documented.

Awesome that you have parsing of comments. A long standing desire is to have better Franca to Documentation generation, and comments are of course critical for that. Doxygen was just an easy way, but I would try generating for example Markdown (or similar) and processing that with Jekyll, Sphinx/ReadTheDocs, AsciiDoc, (or similar) to easily get attractive documentation.

jb090979 commented 7 years ago

I keep track on your generator. If you have questions or you want to request a pyfranca feature please let me know. May I can help you.

zayfod commented 7 years ago

OK. @jb090979 originally I was seeing this as out of scope of pyfranca but I see that @gunnarx has been thinking and working in the same direction. I agree that it makes sense to have an example of how to use pyfranca as a base for custom code generation - it's original purpose.

It seems to me that both of you have been working in the same direction and what remains are implementation details. Is this correct?

tools/franca_gen.py?

jb090979 commented 7 years ago

yes correct.