Skip to content

Add C preprocessor support to JS libraries. - #1969

Closed
juj wants to merge 1 commit into
emscripten-core:incomingfrom
juj:preprocess_js_library
Closed

Add C preprocessor support to JS libraries.#1969
juj wants to merge 1 commit into
emscripten-core:incomingfrom
juj:preprocess_js_library

Conversation

@juj

@juj juj commented Jan 3, 2014

Copy link
Copy Markdown
Collaborator

Implement better support for C preprocessing directives. Enables the use of #if <expression with (), &&, ||, <, >, <=, >=, ==, !=, defined()>. Adds support for #define, #undef, #ifdef, #ifndef, #elif, #warning and #error. Does not (yet?) implement support for preprocessor macros, or text substitution outside preprocessor directives with #define. Add unit test.

…use of #if <expression with (), &&, ||, <, >, <=, >=, ==, !=, defined()>. Adds support for #define, #undef, #ifdef, #ifndef, #elif, #warning and #error. Does not (yet?) implement support for preprocessor macros, or text substitution outside preprocessor directives with #define. Add unit test.
@juj

juj commented Jan 3, 2014

Copy link
Copy Markdown
Collaborator Author

There is a bug that previously committed optimizations silently failed due to C preprocessor not working as expected. Lines like https://github.com/kripken/emscripten/blob/master/src/library_gl.js#L4195 were not properly evaluated, which caused the optimizations to fail.

@kripken

kripken commented Jan 4, 2014

Copy link
Copy Markdown
Member

Curious about the motivation here? Just for future use, or something concrete?

@juj

juj commented Jan 4, 2014

Copy link
Copy Markdown
Collaborator Author

In addition to fixing the abovementioned case where things silently failed with #if A && !B, there's a few places in library_gl.js where I want to do #if A || B, but couldn't, and had to do

#if A
code
#endif
#if B
code
#endif

and duplicate the same section of code. I figured you wouldn't let such a PR pass, so decided to first implement better preprocessor support to be able to do that.

Comment thread src/parseTools.js

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not use a regex?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Regexes aren't that readable or self-descriptive. I think this is more documentative, plus probably faster as well.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am 99% sure this would be much slower, regexes are JITed extremely efficiently in modern JS engines.

@kripken

kripken commented Jan 5, 2014

Copy link
Copy Markdown
Member

My main concern is that this is a big new chunk of code that makes the core compiler more complex, and we would need to maintain in the future.

So I am strongly inclined to specifically fix the issues you mention of #if A && !B and #if A || B. For example, how about if ran eval on what comes after the #if? (perhaps only if it is not a simple identifier, as an optimization)

@juj

juj commented Jan 7, 2014

Copy link
Copy Markdown
Collaborator Author

I thought about eval(), but then rejected it as a deadend since I don't think it will be easily possible to make it support preprocessor expansion, macros, ..., VA_ARGS or # or ## operators in the future if needed. I also searched if there would be an existing C preprocessing library out there implemented in JS, but could not find anything suitable.

People expect a lot of things from their existing knowledge when they see C preprocessing directives. The current code hardcodes the few cases it supports, and silently fails on the ones it doesn't. I don't think it's mature for the project to take the stance that only those preprocessor directives that our src/library_xx.js happen to use are supported, and incrementally keep hardcoding new cases whenever people report bugs against them (those recent #if 1 and #include x.js for example). I wanted to find the proper abstractions here that would have at least some chance of being future-proof, while trying to keep the code in a manageable size. Another route could be to reuse Clang preprocessor with Clang -E option, which would be a full black box process.

@coolwanglu

Copy link
Copy Markdown
Contributor

I wonder if this could be useful: https://github.com/mozilla/pdf.js/blob/master/external/builder/builder.js#L23
In their case, it's actual JS directives in the C style, you can put anything after #if and the expression will be evaluated using vm.runInNewContext.

I don't believe it could support ## though, but maybe the flexibility makes more sense for JS

@kripken

kripken commented Jan 7, 2014

Copy link
Copy Markdown
Member

That looks like nice code. But with a little refactoring I think ours could do everything they do.

@juj, my concern with your code is the size and complexity, in a part of the compiler I really want to keep as simple as possible. I agree we should not fail silently on things we don't support, once we do that, I think we would be in pretty good shape, and if people ask for more features, we could add them like #include was added.

@juj juj closed this Jan 9, 2014
@juj juj mentioned this pull request Aug 22, 2017
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.

3 participants