Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for enums and attributes #13

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Hadatko
Copy link

@Hadatko Hadatko commented Oct 21, 2024

Refactored structs

Refactored structs

Signed-off-by: Cervenka Dusan <[email protected]>
Signed-off-by: Cervenka Dusan <[email protected]>
Signed-off-by: Cervenka Dusan <[email protected]>
Copy link
Owner

@cogu cogu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot approve this pull request as the code is not up to standard for the following reasons:

  • Contains unrelated and off-topic changes
  • Use of empty lists as default values in functions
  • Introduction of attributes is compiler-dependent and needs further consideration
  • Most importantly, it doesn't have any unit tests

If you make a new PR containing just the Enum with passing unit tests I might approve it. Other changes needs to come later.

@@ -136,7 +136,7 @@ class DataType(Element):
"""
Base class for all data types
"""
def __init__(self, name: str | None) -> None:
def __init__(self, name: str = "") -> None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change this? It's off topic

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less complicated API. Because what is difference between "" or None? You are checking for None but not for "". So it is simpler and easier to check for "" then for None and ""

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So based on what you said bellow i understand why you are using None, but still i think it is redundant.

@@ -168,6 +168,45 @@ def qualifier(self, name) -> bool:
else:
raise KeyError(name)

class EnumMember(Element):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be named EnumValue

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually not. It is like StructMember. This is also member of Enum type, which has name and value

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another point of view:
If this should be EnumValue, then StructMember should be StructVariable.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about StructElement?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it is up to you. But it should be usable for both cases. I am coauthor of eRPC project (similar to this) and at the beginning i was lead by USA architect who decided to use StructMember and EnumMember. Sounds good to me.

https://github.com/EmbeddedRPC/erpc/tree/develop/erpcgen/src/types

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be also StructItem and EnumItem

A enum definition
"""

def __init__(self, name: str, members: list[EnumMember] = [], attributes: list[str] = []) -> None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must never use empty list as default value in functions. It's dangerous.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It is valid case, where you have no members.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t's a very common mistake among newcomers to Python. Google it, there are great explanations on the internet.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That just sad.
Ok we can use None. But i wouldn't use one membert type as an option.
so list[EnumMember] | None = None
in a code bellow:
self.members = list(working_list) if working_list else []

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's safer to do a proper check against None.

def __init__(self, name: str, elements:  list[EnumElement] | None = None):
self.elements: list[EnumElement] = []

if elements is not None:
    self.elements = list(elements)

These days however I always take it one step further and double-check that each individual element in the given argument list is of expected type. I usually do this by calling a helper function (usually called append or append_<something> that does the actual check.

@@ -197,17 +236,13 @@ class Struct(DataType):
"""
A struct definition
"""
def __init__(self, name: str | None, members: StructMember | list[StructMember] | None = None) -> None:
def __init__(self, name: str = "", members: list[StructMember] = [], attributes: list[str] = []) -> None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never use empty list as initializer.
Introducing attributes here needs some further design considerations. Attributes are compiler-specific for GCC. What if we are using MSVC? We should introduce the attribute mechanism separately.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, i just need this one so i implemented them this way. But i was thinking to have something like cfiles attribute class

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, i just need this one so i implemented them this way. But i was thinking to have something like cfiles attribute class

self.members: list[StructMember] = members.copy()
else:
raise TypeError('Invalid argument type for "elements"')
self.attributes = attributes.copy()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use copy. If you want to create a new list which is a copy of another, write it as list(attributes).
But as stated above, we should introduce attribute-mechanism later anyway.

@@ -432,7 +438,7 @@ def _write_typedef_usage(self, elem: core.TypeDef):
"""
Writes typedef usage
"""
if not elem.name:
if elem.name == "":
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is making it worse. if not elem.name works equally well if name is an empty string or None. Comparing it to empty string is not the Python way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok i didn't know this one.

@@ -493,7 +501,7 @@ def _write_function_usage(self, elem: core.Function) -> None:
"""
Writes function usage (name of the function)
"""
if not elem.name:
if elem.name == "":
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change this. It's making it worse.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

"""
Writes enum declaration
"""
self._write(f"enum{" ".join([' __attribute__(('+attribute+'))' for attribute in elem.attributes])} {elem.name}")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change only works for GCC-like compilers. Needs some more consideration and design (for example how to specify compiler family).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

def _write_struct_usage(self, elem: core.Struct) -> None:
"""
Writes struct usage
"""
if not elem.name:
if elem.name == "":
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

raise ValueError("struct doesn't have a name. Did you mean to use a declaration?")
self._write(f"struct {elem.name}")

def _write_struct_declaration(self, elem: core.Struct) -> None:
"""
Writes struct declaration
"""
self._write(f"struct {elem.name}")
self._write(f"struct{" ".join([' __attribute__(('+attribute+'))' for attribute in elem.attributes])} {elem.name}")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before. Needs some further consideration.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

@@ -515,6 +515,8 @@ def _write_function_declaration(self, elem: core.Function) -> None:
self._write("static ")
if isinstance(elem.return_type, core.Type):
self._write_type_declaration(elem.return_type)
if isinstance(elem.return_type, core.TypeDef):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is supposed to be here without having a unit test that proves it. Nevertheless it should say elif here and not if.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can chage it to elif. But should work similary.
Well i need it here otherwise i cannot generate my code :D

Copy link
Author

@Hadatko Hadatko Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am doing something like this. Maybe it is not optional. Byt i would like to have function which will return STRING from declaration instead of this hack for cfile.Writer(cfile.StyleOptions()).write_str:

"sizeof({cfile.Writer(cfile.StyleOptions()).write_str(self.cF.sequence().append(self.paramsTypes[param["data"].type]["C"]))})"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok this change is not necessary as i should use self.cF.func_call("sizeof", [self.paramsTypes[param["data"].type]["C"]]) instead of what i mentioned. I am developing under pressure a bit and lack of documentation is not helping :D

ELSE = 2


class Condition(Block):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you're taking shortcuts. Not all if-statements are wrapped in braces.
In C you can declare statements like this:

if(condition) ++x; else ++y;


def _write_condition(self, elem:core.Condition) -> None:
if elem.type == core.ConditionType.IF:
self._write(f"if ({elem.condition})")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add support for new formatting styles in style.py then support it in writer.py

  • Space after if but before parenthesis? if( vs. if (
  • Space around the condition? (condition) vs. ( condition )

@cogu
Copy link
Owner

cogu commented Oct 24, 2024

You're taking too many shortcuts in the design. You don't add style formatting options in the writer and don't do any unit testing.

I think you should continue working directly on your fork. I'm sure you can repurpose the code to fit your specific needs.
I should close this PR.

@Hadatko Hadatko marked this pull request as draft October 24, 2024 19:41
@Hadatko
Copy link
Author

Hadatko commented Oct 24, 2024

Hi @cogu , i convert PR to draft. Of course i am taking shortcuts as there are too many missing features. I think you shouldn't close PR yet. You can update your code base on this in correct way. After then i would close this branch. Otherwise i would keep it here as an inspiration for people who would miss same features...

Later i can provide better PRs divided by features. E.g. adding enums, fix blank line, ...

@Hadatko Hadatko force-pushed the feature/addEnumsMainly branch 4 times, most recently from 93d296f to 9decef9 Compare November 7, 2024 17:53
@Hadatko Hadatko force-pushed the feature/addEnumsMainly branch 3 times, most recently from 8da198e to 5c3c3c1 Compare November 12, 2024 13:55
@Hadatko Hadatko force-pushed the feature/addEnumsMainly branch from 5c3c3c1 to 0240797 Compare December 15, 2024 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants