On Wed, Dec 9, 2015 at 5:08 PM, <vish...@stanford.edu> wrote: > Indeed, my use case is also writing proper tests for macros using FactCheck. > I have a more bizarre use case which involves writing a lisp using julia > (learning purposes only), but it's more out there. > > In this case, it'd be nice to verify that the expression I get matches the > one I expect. > Is there a way process an Expression and ignore nodes (i.e, linenumbernode, > which has absolutely nothing to do with expression equality, and represents > internal julia metadata)? It'd be a tree traversal function, maybe, but I'm > unable to find any documentation on how to manipulate Expression objects. > Even something like cons/first/rest would be sufficient for my case.
Expr is just a normal object and you can access the head and args fields. > > On Wednesday, December 9, 2015 at 1:26:14 PM UTC-8, Erik Schnetter wrote: >> >> I want to test the expression >> >> ``` >> macroexpand(:@fastmath :+) >> ``` >> >> where `:+` is a symbol, not a function. >> >> I wasn't able to determine the difference. I used both `info` and `dump`, >> and my LHS (the result of the expression above) and what I constructed >> manually looked identical, and in the REPL, the epression >> >> ``` >> macroexpand(:@fastmath :+) == :(:+) >> ``` >> yields `true`. In `test/fastmath.jl`, it didn't. (It works fine for five >> other expressions that are currently being tested.) >> >> Anyway -- my point being that it can be quite useful to compare >> expressions, even if the exact value might change over time. Since Julia's >> macros are all about manipulating expressions, having ways to output, >> serialize, load, compare, and treat them like any other data makes totally >> sense. >> >> -erik >> >> >> >> On Wed, Dec 9, 2015 at 4:05 PM, Yichao Yu <yyc...@gmail.com> wrote: >>> >>> On Wed, Dec 9, 2015 at 3:57 PM, Erik Schnetter <schn...@gmail.com> wrote: >>> > Comparing expressions is useful if you want to write a test case for a >>> > function that transforms expressions, such as e.g. `@fastmath`. I >>> > recently >>> > added some test cases, but was unable to test the result of >>> > >>> > macroexpand(:@fastmath :+) >>> > >>> > since I don't know how to explicitly construct the expected result. I >>> > know >>> > how to do it in the REPL, but this doesn't work in test cases. >>> >>> What's the difference between REPL and test script? >>> >>> julia -f -e 'println(macroexpand(:(@fastmath +)) == >>> :(Base.FastMath.add_fast))' >>> true >>> >>> >>> > >>> > -erik >>> > >>> > >>> > On Wed, Dec 9, 2015 at 3:46 PM, Yichao Yu <yyc...@gmail.com> wrote: >>> >>> >> >>> >> On Wed, Dec 9, 2015 at 3:05 PM, <vis...@stanford.edu> wrote: >>> >> > Interesting. I didn't think to use dump to check differences. >>> >> > >>> >> > Another followup question. After using dump on some simple if >>> >> > statements, >>> >> > I've noticed that all blocks induce this LineNumberNode which is >>> >> > messing >>> >> > up >>> >> > the equality. >>> >> > Is there a way to ignore these nodes in the equality check? They >>> >> > show up >>> >> > in >>> >> > any kind of block statement (function, if, etc) >>> >> > >>> >> >>> >> May I ask what do you need the equality of expressions for? It doesn't >>> >> sound like a too useful concept. There can be expressions that are >>> >> equal but have different side effects due to the variables they >>> >> capture (try constructing `Expr(:call, :push!, [1, 2], 1)` twice and >>> >> eval/compare them). There can also be expressions that are equivalant >>> >> but appears differently. >>> >> >>> >> In general, I never find `==` of expressions too useful. When >>> >> processing it, you can just ignore the line number nodes if you don't >>> >> care too much about debug info (also see base/docs/Docs.jl for some >>> >> example of stripping unwanted part from a expression). There's also >>> >> MacroTools.jl which provides a nice way to process expressions. >>> >> >>> >> > eg: >>> >> > >>> >> > dump(:(if true 1 else 0 end)) >>> >> > >>> >> > Expr >>> >> > >>> >> > head: Symbol if >>> >> > >>> >> > args: Array(Any,(3,)) >>> >> > >>> >> > 1: Bool true >>> >> > >>> >> > 2: Expr >>> >> > >>> >> > head: Symbol block >>> >> > >>> >> > args: Array(Any,(2,)) >>> >> > >>> >> > 1: LineNumberNode >>> >> > >>> >> > file: Symbol none >>> >> > >>> >> > line: Int64 1 >>> >> > >>> >> > 2: Int64 1 >>> >> > >>> >> > typ: Any >>> >> > >>> >> > 3: Expr >>> >> > >>> >> > head: Symbol block >>> >> > >>> >> > args: Array(Any,(2,)) >>> >> > >>> >> > 1: LineNumberNode >>> >> > >>> >> > file: Symbol none >>> >> > >>> >> > line: Int64 1 >>> >> > >>> >> > 2: Int64 0 >>> >> > >>> >> > typ: Any >>> >> > >>> >> > typ: Any >>> >> > >>> >> > >>> >> > dump(Expr(:if, true, Expr(:block, 0), Expr(:block,1))) >>> >> > >>> >> > Expr >>> >> > >>> >> > head: Symbol if >>> >> > >>> >> > args: Array(Any,(3,)) >>> >> > >>> >> > 1: Bool true >>> >> > >>> >> > 2: Expr >>> >> > >>> >> > head: Symbol block >>> >> > >>> >> > args: Array(Any,(1,)) >>> >> > >>> >> > 1: Int64 0 >>> >> > >>> >> > typ: Any >>> >> > >>> >> > 3: Expr >>> >> > >>> >> > head: Symbol block >>> >> > >>> >> > args: Array(Any,(1,)) >>> >> > >>> >> > 1: Int64 1 >>> >> > >>> >> > typ: Any >>> >> > >>> >> > typ: Any >>> >> > >>> >> > >>> >> > They're the same minus LineNumberNodes, because block type >>> >> > expressions >>> >> > always create those things. >>> >> > >>> >> > >>> >> > On Wednesday, December 9, 2015 at 7:21:55 AM UTC-8, STAR0SS wrote: >>> >> >> >>> >> >> You can also use dump() on your expressions to see how they differ >>> >> >> exactly. The normal printing doesn't really show you much. >>> > >>> > >>> > >>> > >>> > -- >>> > Erik Schnetter <schn...@gmail.com> >>> > http://www.perimeterinstitute.ca/personal/eschnetter/ >> >> >> >> >> -- >> Erik Schnetter <schn...@gmail.com> >> http://www.perimeterinstitute.ca/personal/eschnetter/