<div><br></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 11, 2020 at 14:55 connor horman <<a href="mailto:chorman64@gmail.com">chorman64@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)"><div><div dir="auto">This seems similar in goal (and somewhat similar in style) to rust's declarative macros. Would this be able to support similar things to that, or would that be beyond the scope of this?</div></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 11, 2020 at 14:32 Min-Yih Hsu via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)"><div style="word-wrap:break-word;line-break:after-white-space">Hi Clang folks,<div><br></div><div>Recently I have been working on a side project, Nacro (<a href="https://github.com/mshockwave/nacro" target="_blank">https://github.com/mshockwave/nacro</a>), that you might find interesting.</div><div><br></div><div><span style="color:rgb(0,0,0)">Nacro is a small DSL aim to provide a better C/C++ macro experience. Here is an example:</span></div><div><span style="color:rgb(0,0,0)">```</span></div><div><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;padding:16px;overflow:auto;line-height:1.45;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;font-variant-ligatures:normal;background-color:rgb(246,248,250);color:rgb(36,41,46)">#<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">pragma</span> nacro rule myPrint
(val:$expr) -> $stmt {
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">printf</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(3,47,98)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">"</span>%d<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">\n</span><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">"</span></span>, val * <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">2</span>)
}

#<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">pragma</span> nacro rule genColors
(cases:$expr*) -> {
    $<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">loop</span>(c in cases) {
        <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">case</span> c:
        <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">printf</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(3,47,98)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">"</span>the color is %s<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">\n</span><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">"</span></span>, $<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">str</span>(c));
        <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">break</span>;
    }
}

<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">enum</span> Color { RED, BLUE, YELLOW };
<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">void</span> <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(111,66,193)">printColor</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">enum</span> Color color) {
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">switch</span>(color) <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">genColors</span>(RED, BLUE, YELLOW)
}

<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">int</span> <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(111,66,193)">main</span>() {
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">myPrint</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">1</span> + <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">3</span>)   <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(106,115,125)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">//</span> print out '8'</span>
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">printColor</span>(RED); <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(106,115,125)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">//</span> print 'the color is RED'</span>
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">return</span> <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">0</span>;
}</pre></div><div><span style="color:rgb(0,0,0)">```</span></div><div><span style="color:rgb(0,0,0)">You can create a nacro rule with a pragma directive and follows with definitions written a simple DSL. The defined nacro rule works just like a normal macro function (i.e. expanded during preprocessing and called like a function), but with some extra features:</span></div><div><font style="color:rgb(0,0,0)"> - Multiline definitions without ‘\’.</font></div><div><font style="color:rgb(0,0,0)"> - Expression Protection: As shown in the ‘myPrint’ nacro above, you don’t need to add parens around expressions anymore, the nacro preprocessor will do that for you.</font></div><div><font style="color:rgb(0,0,0)"> - Loops, one of the most exciting features in nacro: You can use “$loop” directive to ‘unroll’ a list of argument (argument type trailing with ‘*’, like ‘$expr*’. It’s equivalent to VA_ARGS) during preprocessing.</font></div><div><font style="color:rgb(0,0,0)"> - Detecting invalid capturing. This is still an unstable feature, but basically it’s aiming to detect issues like this:</font></div><div><font style="color:rgb(0,0,0)">```</font></div><div><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;padding:16px;overflow:auto;line-height:1.45;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;font-variant-ligatures:normal;background-color:rgb(246,248,250);color:rgb(36,41,46)">#<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">define</span> <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(111,66,193)">foo</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(227,98,9)">arg</span>) {\
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">int</span> x = <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">0</span>;  \
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">return</span> arg + x; \
}

<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(106,115,125)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">//</span> ERROR: caller will always return 0 </span>
<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(106,115,125)"><span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace">//</span> regardless the argument value</span>
<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">int</span> <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(111,66,193)">caller</span>(<span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(215,58,73)">int</span> x) {
    <span style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;color:rgb(0,92,197)">foo</span>(x)
}</pre><div><br></div></div><div><font style="color:rgb(0,0,0)">```</font></div><div><font style="color:rgb(0,0,0)">Please checkout the its wiki page (</font><a href="https://github.com/mshockwave/nacro/wiki/Invalid-Capture-Detection" target="_blank">https://github.com/mshockwave/nacro/wiki/Invalid-Capture-Detection</a><span style="color:rgb(0,0,0)">) for more info.</span></div><div><span style="color:rgb(0,0,0)"><br></span></div><div><font style="color:rgb(0,0,0)">Another important thing is that nacro _doesn’t require a custom Clang / LLVM_. All of the features are implemented in a Clang plugin. So all you need is a Clang 10 by your hand and the plugin.</font></div><div><font style="color:rgb(0,0,0)"><br></font></div><div><font style="color:rgb(0,0,0)">Though not modifying Clang actually put a tons of restrictions and force me to create many hacky workarounds that might be broken in newer version of Clang. For example, as a preprocessor plugin, all i can do is mutating and injecting tokens. But the preprocessor doesn’t like it, or in other words, current preprocessor doesn’t have a good support on this kind of actions. Especially while I was dealing with SourceLocation: there are many time i need to use an imprecise one or even fake one.</font></div><div><font style="color:rgb(0,0,0)"><br></font></div><div><font style="color:rgb(0,0,0)">Another hard part is the Invalid Capture Detection. My original plan was to </font><span style="color:rgb(0,0,0)">automatically </span><font style="color:rgb(0,0,0)">fix it rather than throwing an error message. However, that will require symbol table and scope info that merely exist in AST. Though Parser/Sema has those info but currently we don’t have any plugin support on Parser/Sema. </font></div><div><font style="color:rgb(0,0,0)"><br></font></div><div><font style="color:rgb(0,0,0)">Hope you find this project interesting, or at least find it amusing. </font></div><div><font style="color:rgb(0,0,0)"><br></font></div><div><font style="color:rgb(0,0,0)">-Min</font></div></div>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div></div>
</blockquote></div></div>