Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Sandy Maguire
    @isovector
    the haskell lexer turns layout indent and dedent into tokens. maybe that approach could work?
    some sort of new delimiter in comby that says "hey, i'm a layout delimiter" which records the indentation it's at when it gets matched, and adds that to any new lines?
    Ryan Greenberg
    @ryangreenberg

    I just started using comby and really enjoy it—thank you! I have a question that seems really basic but I couldn't figure it out from the docs. How do I limit a hole to a certain number of arguments? For example, in https://bit.ly/3q59MTs I want to match and rewrite the first two lines, but not the third:

    foo(1, 2)
    foo(1, boo(2, 3))
    foo(1, 2, true, 3)

    I can match everything with foo(:[a], :[b]); I can match just the third line with foo(:[a], :[b], :[rest]), but I can't figure out how to match only two arguments.

    Rijnard van Tonder
    @rvantonder

    Hey @ryangreenberg, bit late responding here. You probably want to try something like this to match 2 arguments:

    foo(:[a:e], :[b:e])

    Example: https://bit.ly/32g4c8C

    What's happening there is :[a] and :[b] are restricted to matching "expression-like" syntax and won't continue matching across whitespace at the same block or expression level. There isn't a built-in notion for matching arguments (or a certain number of them), but I think you can make progress by using the hole that matches expression-like syntax (where arguments generally correspond to arguments).

    There's a longer description in the docs: https://comby.dev/docs/syntax-reference.

    1 reply
    John Austin
    @Kleptine
    I'm not sure if I should have created an issue or posted here, but I've hit an issue trying to install comby on windows: comby-tools/comby#329
    jtrakk
    @jtrakk
    I'm thinking about porting a functional-style rust library to another language. Does anybody use comby to help with that kind of thing?
    5 replies
    François Proulx
    @francoisproulx_twitter

    Hello. I'm new to Comby. I find the idea really awesome and I was wondering if I could not use it for one of my project. To keep it simple, I would like to take a snippet of code (I need to support many languages such as Python, Javascript, HTML, etc..) and basically strip out comments (potentially multiline) as well as non meaningful whitespaces (for instance in Python the indentation matters, but in Javascript it could essentially be collapse to one line)

    Maybe Comby is not the right tool for the job, but when I see that it has support for all the languages I need and all the hard work of parsing the syntax has been done, I though there might be a way.

    Rijnard van Tonder
    @rvantonder

    hey @francoisproulx_twitter! so in short, there isn't an exact way to strip out comments, but there may be ways to do something like that. basically, comments are treated like whitespace, and right now it's not possible to match directly on comments. It's something that may be possible in future, but not right now. Right now, you could, for example, match all whitespace in some code (which will include comments) and then filter out the parts that are just whitespace with a submatch (regex), leaving only the comments.

    as well as non meaningful whitespaces (for instance in Python the indentation matters, but in Javascript it could essentially be collapse to one line)

    this is tricky with comby, it doesn't recognize different kinds of whitespace (no whitespace is meaningful). this means that matching or preserving indentation-sensitive (AKA layout-sensitive) syntax doesn't work out of the box.

    It sounds like you want to do some kind of normalization on code (you mentioned a "stable fingerprint" in the tweet :-)). I think you can achieve a good degree of this by just normalizing whitespace and stripping out comments like your idea, but I don't see a clear way of dealing with layout-sensitive languages (e.g., Python). A hacky way to deal with Python, for example, could be to run pyindent (which will add braces to blocks) and which comby can then process and "normalize". So you can then map python code to this footprint, but the stable footprint/representation of the Python code will not match the source input, which could be a problem depending on what you want to do with those snippets.

    François Proulx
    @francoisproulx_twitter
    @rvantonder ok so you seem to suggest that I could have a query to match all whitespace, including comments, then replace with "" (ie strip ? How would you do that exactly? I imagine that significant whitespaces wil remain (for instance: def myfunc(a): in Python where the space between def and myfunc is needed)
    Rijnard van Tonder
    @rvantonder

    @francoisproulx_twitter ah you know what, I tried to grab you an example but I think it's not quite possible the way I thought you could do it. The best kind of stripping you can do right now is along that idea, you just match whitespace (a space " ") and replace with a space (" "). This will strip comments. Example (note, the match and rewrite parts are just a space): https://bit.ly/35xEcXW

    Sadly, this will not preserve the number of whitespace or newlines (which is what I thought would be possible), so it all ends up on one line. The trouble is that there isn't a way to refer to the matched whitespace. If there were, you could preserve the matched parts and more carefully strip out comments. So I don't know if this is helps. Note that you can still use comby generally to match, say, on function bodies, and strip out comments within function bodies with the same idea (so you would get the function body, one on each line), by using a rewrite rule. But again, you cannot preserve the whitespace within that body. Example: https://bit.ly/3HBuhit

    8 replies
    GMIKE
    @RomanSoloweow

    Can i rewrite under a certain condition?
    For example, replace sign with ">" only if it's equal to "<"

    My exampl: bit.ly/337HaBN

    1 reply
    image.png
    Daniel Hines
    @d4hines
    Hi @rvantonder . Is there a way to run a rewrite to fixed point, without scripting it in bash?
    Rijnard van Tonder
    @rvantonder
    hey @d4hines, nope, sorry :(
    GMIKE
    @RomanSoloweow

    Hi @rvantonder, Is there an example written in Comby to convert if-else chains to a switch-case construct?

    I wonder how it is described for if-else of any nesting

    1 reply
    Señor Agosto
    @SenorAgosto
    Hi all, I'm trying to match recursive function calls in TypeScript can anyone help me with the match syntax for that?
    1 reply
    GMIKE
    @RomanSoloweow
    How does Comby select value1, why "Result1" and not "Result1;"?
    image.png
    GMIKE
    @RomanSoloweow
    @rvantonder
    Rijnard van Tonder
    @rvantonder
    @RomanSoloweow it's like regex capture groups: if you have a pattern like (match); the group (...) is going to store the value match and ; is not going to be part of it. it is lazy (will stop matching when it sees the first ;): https://comby.dev/docs/syntax-reference. If you want to include the ; use :[value.]
    2 replies
    actually, :[value.] won't work for you here because I see the data is a string. In this case, your best idea is to reintroduce the ; in the output
    GMIKE
    @RomanSoloweow

    I don't quite understand how it works. After all, if you specify ";" two times, then ";" will be part of the value
    Example: bit.ly/3Iv5Sve

    image.png

    Rijnard van Tonder
    @rvantonder
    it's the same as what regex would do. remember your pattern isn't just ending in ;. it is not just ending on that line. it is ending in ; <newline>else return... and the match will be found depending on the content that satisfies the entire suffix. again, same as regex: https://regexr.com/6gabn
    Screenshot 2022-02-26 180645.png
    the x; with ; is also captured if you add a ; there
    Monty Zukowski
    @montyz
    I need to translate method calls like Activity.list().last() to (await (await Activity.list()).last()) in a generic way. I was hoping to use :[var.] syntax but that doesn't include the parens. I'm guessing this is more of a tree transformation than the kind of substitution that comby can do. I'd love to be proven wrong though!
    Monty Zukowski
    @montyz
    Or if you have a suggestion for another tool that could do that, let me know.
    Monty Zukowski
    @montyz
    @rvantonder any ideas on the above question?
    Rijnard van Tonder
    @rvantonder
    try :[var:e] syntax:
    like this @montyz: https://bit.ly/3sLsiTv
    it will also match any arguments inside (...), including spaces
    Monty Zukowski
    @montyz
    Ah, I see, but I have to know how many function invocations are in the chain in advance in this case. There's no way to implement it in a generic recursive way I assume. Also, I made a slight change to get the output I desire, in case someone looks at this in the future. bit.ly/3Mwxbrj
    comex
    @comex
    Hello, is there a simple way to require the match to be at word boundaries? For example, match bar() without matching foobar(). I was able to make it work by putting :[~\b] before the word, but that feels like an oddly complex way to invoke a behavior that, if anything, I'd expect to be the default. Just wondering.
    Rijnard van Tonder
    @rvantonder
    @comex you can try add -disable-substring-matching on the command line which effectively adds word boundaries around the pattern
     echo "bar() foobar()" | comby -stdin -disable-substring-matching "bar()" "yo" -m .generic
    Rijnard van Tonder
    @rvantonder
    It's not the default behavior (but note I have thought about it that much) because if the converse were the default, there'd be questions about an option/mechanism to very well enable matching on substrings (which may be a more common desire, if you're coming from a text replacement tool where substring matching is the default, a la sed). I haven't had many questions/confusion about this property, but if there were more cases like this I would start thinking about changing the default. Usually, it seems, replacements have enough specificity that this issue doesn't come up that often.
    slim16165
    @slim16165
    Hi everyone!
    Sorry for my english, it's not my first language.
    I've opened this question here: comby-tools/comby#334
    now I clearly understand how comby is working but not why it's working in this way
    I've tried an experiment: bit.ly/3uvWaUH
    slim16165
    @slim16165
    My doubt is about the PHP semantic: {$plugins and { $plugins are the same for the PHP compiler. RegEx care about string and spaces, but not a compiler or an interpreter.
    slim16165
    @slim16165

    I would have expected that the wanted behaviour would be to ignore the extra spaces in the search query provided to comby (parsing the following query
    {<space>:[p]
    in my idea should return

    <bracket><spaces>?<any_variable_or_statement_or_nothing>

    but the actual translation is with the spaces mandatory

    <bracket><spaces><any_variable_or_statement_or_nothing>

    In regex there is a modifier called Free spacing, do you plan to have something similar in the future?
    GMIKE
    @RomanSoloweow
    Hello, @rvantonder
    bit.ly/3Lcmh9g
    Comby's behavior seems strange. Looks like a bug
    image.png
    Tharun M Paul
    @tmpaul
    What is the best way to match an identifier with double quotes ? In this example: bit.ly/37ObYd3 I'm trying to match an import statement where the dependency is "b" (escaped double-quotes)
    1 reply
    Matthew Johnson
    @ajohnsonz

    Hi all - wondering if someone could help me understand how the whitespace matching works. I'm trying to move a method expectation into the method, something like:

        @Test(expected = IllegalArgumentException.class)
        public void lengthOf7CannotSupportMoreThan90Years() {
            ReferenceEncoder unitUnderTest = new ReferenceEncoder(LENGTH_FOR_90_YEARS);
            unitUnderTest.getBase64FromLong(millisInMoreThan90Years);
        }

    should become

        @Test
        public void lengthOf7CannotSupportMoreThan90Years() {
        org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, ()-> {
        ReferenceEncoder unitUnderTest = new ReferenceEncoder(LENGTH_FOR_90_YEARS);
            unitUnderTest.getBase64FromLong(millisInMoreThan90Years);
        });
    }

    Using this recipe:

    match='''@Test(expected = :[ex])
    public void :[testname]() {
    :[testbody]
    }'''
    
    rewrite='''@Test
    public void :[testname]() {
        org.junit.jupiter.api.Assertions.assertThrows(:[ex], ()-> {
    :[testbody]
        });
    }'''

    This works, however, it's chopping the indentation off the first line. So I thought I could use :[ var] (as per the documentation here https://comby.dev/docs/syntax-reference) to match the whitespace at the beginning of the first line, and reinsert it afterwards, something like:

    match='''@Test(expected = :[ex])
    :[ ws1]public void :[testname]() {
    :[testbody]
    :[ ws2]}'''
    
    rewrite='''@Test
    :[ ws1]public void :[testname]() {
        org.junit.jupiter.api.Assertions.assertThrows(:[ex], ()-> {
    :[testbody]
        });
    :[ ws2]}'''

    But when I do this, it no longer matches my method at all (I have also tested this on the web playground, and it doesn't match there either). Any suggestions?

    3 replies
    Vincent Driessen
    @nvie_twitter

    Hey! Comby is so awesome 😍 I have one question regarding structural rewriting and ignoring whitespace. I'm in a TS/JS code base, so I'm using Prettier to take care of formatting. When I want to rewrite expressions of the form expect(xxx).toEqual(yyy), then it depends whether those are formatted on one line, or over multiple lines, and I wonder if there is a mode in which to use comby where I can effectively treat the punctuation like ( and ) as a pattern that eats up surrounding whitespace as well? Perhaps with a flag on the cmdline or something?

    Ideally, there would be some kind of mode where it would not care about how I write my input expression, i.e. 'foo(x, y: z)', or 'foo ( x , y : z ) ' or 'foo(x,y:z)' would all work as the first argument to comby, and mean the same thing.

    I would want to write:

    comby 'expect(:[1]).toEqual(JSON.stringify(:[2]))' 'expect(JSON.parse(:[1])).toEqual(:[2])' -i ts

    But to do what I want I effectively write this pattern first, and then "hack" support for what I want into it, by adding :[~\s*] holes manually, like so:

    comby 'expect:[~\s*](:[~\s*]:[1]:[~\s*]):[~\s*].:[~\s*]toEqual:[~\s*](:[~\s*]JSON:[~\s*].:[~\s*]stringify:[~\s*](:[~\s*]:[2]):[~\s*])' 'expect(JSON.parse(:[1])).toEqual(:[2])' -i ts

    Of course, this will destroy whitespace in the output, but I don't care, because that's trivial to fix by re-running prettier.

    Is there an option for this? Thx! 🙏

    Similarly, I'd love to know if there is a mode to treat identifiers to include surrounding word boundaries, so foo would not match myfoo. I'm currently doing that by surrounding my identifiers with :[~\b] markers… :grimacing: Not sure if I'm doing this wrong… :smile: