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

Support bindings for literal defines #50

Merged
merged 10 commits into from
Jun 22, 2018
Merged

Conversation

kornilova203
Copy link
Member

@kornilova203 kornilova203 commented Jun 12, 2018

Part of #4

Currently the code only finds defines and does not generate any code for it.

I think it would be better to implement end-to-end testing before moving to this one #51

@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch 2 times, most recently from cc24b1b to 458aa66 Compare June 12, 2018 12:24
@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from 458aa66 to 1ce2e45 Compare June 17, 2018 09:46
@kornilova203 kornilova203 changed the title [WIP] Support bindings for defines [WIP] Support bindings for literal defines Jun 17, 2018
@kornilova203
Copy link
Member Author

kornilova203 commented Jun 17, 2018

I decided that literals will be places directly to Scala code, so their values will be known by a programmer without looking into header file (see Support Bindings for Defines Design Doc)

This commit will be only about literals.

Currently there are following issues:

  • We need to find a way to get Scala type for numeric_constant token.
    For example, we need to know that this token 10000000000 is Long, so we can correctly use it in a Scala file:
    object DefineDefines {
      val LONG: native.CLong = 10000000000L
    }
  • Find a way to follow chain of defines.
    Example:
    #define INT 42
    #define INT_2 INT
  • Check that defines are not undef below in the header
  • Check that DefineFinderAction does not sees a define if #if/ #ifdef directive above the define is false.
  • Handle negative numbers correctly. They consist of 2 tokens

@kornilova203
Copy link
Member Author

Last commit is incorrect, I'll fix it tomorrow

llvm::errs() << "IR is not empty. Please use new instance of "
"ScalaFrontendActionFactory.\n";
llvm::errs().flush();
}
Copy link
Member

Choose a reason for hiding this comment

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

Yes I guess this is pointless now.

bindgen/Main.cpp Outdated

DefineFinderActionFactory defineFinderActionFactory(ir);
Tool.run(&defineFinderActionFactory);
Copy link
Member

Choose a reason for hiding this comment

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

Let's check the returned result code

llvm::errs().flush();
}
} else if (finalToken->isAnyIdentifier()) {
// TODO: save identifier and get its type in ScalaFrontendAction
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to use while (token->isAnyIdentifier()) in getFinalIdentifier() so this branch never happens?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because finalToken might still be anyIdentifier, since not all defines have literal values.
So the loop may never end. But I can reorganize the code so it will be a bit more clear

Copy link
Member Author

Choose a reason for hiding this comment

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

We need this branch because we want to find defines that are aliases for variables.

}

const clang::Token *
DefineFinder::getFinalIdentifier(const clang::Token &token) const {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not familiar with the AST but I suggest renaming this method to resolveIdentifier() and recursively call it on a token until we resolve it to a literal or something we don't handle. Maybe I misunderstood something here though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Name is good
It should be called recursively until the identifier is not an another define, but the problem is that defines may contain multiple tokens:

extern int a;
#define MY_A a
#define MY_A_PTR MY_A * // two tokens, one of them is another define

So the function might get too complicated. I'll try to find clang function that will resolve value of define for us

: ir(ir), compiler(compiler), pp(pp) {}

void DefineFinder::MacroDefined(const clang::Token &MacroNameTok,
const clang::MacroDirective *MD) {
Copy link
Member

Choose a reason for hiding this comment

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

From a style point of view I find it confusing to have variable names starting with upper. We don't do it for ir.

Copy link
Member Author

Choose a reason for hiding this comment

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

The names are from the overriden methods, but they can be renamed


extern int a;
#define MY_A a // unsupported

Copy link
Member

Choose a reason for hiding this comment

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

#define wait_for_it(cond) do { sleep (1000); } while (!cond)

bindgen/ir/IR.h Outdated
@@ -28,6 +29,11 @@ class IR {
void addUnion(std::string name, std::vector<Field> fields,
uint64_t maxSize);

void addLiteralDefine(std::string name, std::string literal);

void addLiteralDefine(std::string name, std::string literal,
Copy link
Member

Choose a reason for hiding this comment

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

Can type have a default value to reduce this to one method?

Copy link
Member Author

Choose a reason for hiding this comment

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

LiteralDefine always have a type now, so I can simply delete the method without a type

@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from c0bbf73 to c8c7543 Compare June 18, 2018 07:43
@kornilova203
Copy link
Member Author

I couldn't find a function that would expand a define.
My expandDefine implementation is able to follow only a simple chain of defines:

#define INT 42
#define INT_2 INT

But I think it shouldn't be a big problem to write the implementation that handles more difficult cases.

Once we expand a define we need to process it. If it is a literal then there is no problems to embed it in the Scala code, but if it's not then we need to find a way to check if it's a variable of data type or of pointer type (or something else). Currently I don't know how to do that.

@kornilova203
Copy link
Member Author

Tests in a container fail because clang API changed since version 4.0
I need to update to 5.0v
We also may want to note somewhere that only versions >= 5.0 are supported

@kornilova203
Copy link
Member Author

kornilova203 commented Jun 18, 2018

To check is a define is an alias for a variable maybe it is a good idea to generate C code that includes the header and uses the value, feed it into FrontendAction and see if there will be errors

@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch 2 times, most recently from 7b81274 to 5a67df5 Compare June 19, 2018 07:58
@kornilova203 kornilova203 requested a review from jonas June 19, 2018 07:58
@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from 5a67df5 to fad3366 Compare June 19, 2018 08:16
@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from fad3366 to e288ac9 Compare June 19, 2018 08:20
@kornilova203
Copy link
Member Author

I think saving all floating point numbers as native.CDouble is good enough for now.

@kornilova203 kornilova203 changed the title [WIP] Support bindings for literal defines Support bindings for literal defines Jun 19, 2018
@kornilova203
Copy link
Member Author

Maybe some of C literals are not valid literals in Scala, so it also has to be checked

@jonas
Copy link
Member

jonas commented Jun 20, 2018

We can test against LLVM 4 if you want. It would however be nice to support more recent versions.

Copy link
Member

@jonas jonas left a comment

Choose a reason for hiding this comment

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

LGTM

@jonas
Copy link
Member

jonas commented Jun 20, 2018

I suggest to wait with merging this until 0.1 has been tagged.

@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from 0537917 to 41585a3 Compare June 21, 2018 14:46
@kornilova203 kornilova203 force-pushed the support-bindings-for-defines branch from 41585a3 to 2db8071 Compare June 21, 2018 18:26
@kornilova203 kornilova203 changed the base branch from master to 0.2 June 22, 2018 17:47
@kornilova203 kornilova203 merged commit 7b0bccb into 0.2 Jun 22, 2018
@kornilova203 kornilova203 deleted the support-bindings-for-defines branch June 23, 2018 13:58
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