Re: more help with an AST
Hi Jochen, Thanks for getting back to me. Responses inline. On 07/12/2017 02:02 AM, Jochen Theodorou wrote: On 11.07.2017 22:07, Ed Clark wrote: [...] the browser shows a post-xform output of: sum = myCtx.multiply( le, re) <--- this executes sum = myCtx.multiply( le, re) <--- this doesn't But, when run, the first line works while the second one results in a MissingMethodException stating there is no "multiply" method for the type Complex - which is the type of "le". can you give me the full exception text? I need to know the number and types of arguments Caught: groovy.lang.MissingMethodException: No signature of method: withctx.math.Complex.multiply() is applicable for argument types: (withctx.math.Complex) values: [0] groovy.lang.MissingMethodException: No signature of method: withctx.math.Complex.multiply() is applicable for argument types: (withctx.math.Complex) values: [0] at withctx.matrix.BraKet$_multiply_closure13$_closure28.doCall(BraKet.groovy:176) The two interesting points to me here are 1) there's only one value ("0") for the missing method "multiply" and 2) the missing method is for the class Complex. This makes me think that the method involved is "le.multiply( re)". ("le" and "re" are both instances of Complex, and at this point in the execution they both have a value which prints as "0".) [...] Drilling down in the AST itself, I'm not seeing any difference - other than line numbers and column numbers - between the various *Expressions (e.g. VariableExpression) making up the subtrees for the two lines. Can you write down how the AST looks like? For VariableExpressions I would be also interested in the accessedVariable and in generalabout what phase we are actually talking about. The phase used by the AST browser is "Instruction Selection"; the phase specified for the xform is "SEMANTIC_ANALYSIS". (I wanted to make sure that the browser was past the action of the xform.) The pre-xform code is // inner product T multiply( Bra left, Ket right) { T sum compCtx.withContext { (0..size - 1).each { idx -> // use some local variables to get the generic type because I // haven't done the code to extract the type through a "getAt" method call T le = left[idx] T re = right[idx] println 'compCtx.multiply gives ' + compCtx.multiply( le, re) println 'compCtx.* gives ' + ( le * re) if (idx == 0) sum = le * re else sum = sum + le * re } } return sum } (The two println's are in there for debugging purposes so the failure happens on something simpler than an if statement.) The post-xform code shown in the browser is public java.lang.Object multiply(withctx.matrix.Bra left, withctx.matrix.Ket right) { java.lang.Object sum = compCtx.withContext({ compCtx .__contextPtr = 0 java.lang.Object __rtContexts = [ compCtx ] compCtx .__contextStack = __rtContexts (0.. size - 1).each({ java.lang.Object idx -> java.lang.Object le = left [ idx ] java.lang.Object re = right [ idx ] this.println('compCtx.multiply gives ' + compCtx.multiply(le, re)) <- this runs fine this.println('compCtx.* gives ' + compCtx.multiply(le, re)) < this is line 176 if ( idx == 0) { sum = compCtx.multiply(le, re) } else { sum = compCtx.plus(sum, compCtx.multiply(le, re)) } }) __rtContexts = __rtContexts.dropRight(1) }) return sum } (To my untrained eye, the xform did exactly what I want the "le * re" method calls have been replaced by "compCtx.multiply(le,re)".) For the line 176 (with fails), the AST in the browser looks like: -- ExpressionStatement - MethodCallExpression MethodCall - this.println((compCtx.* gives + compCtx.multiply(le,re))) -- Variable - this : java.lang.Object -- Constant - println : java.lang.String -- ArgumentList - ((compCtx.* gives + compCtx.multiply(le,re))) Binary - (compCtx.* gives + compCtx.multiply(le,re)) -- Constant - compCtx.* gives : java.lang.String -- MethodCall - compCtx.multiply(le,re) Variable - compCtx : withctx.math.Field -> withctx.math.Field java.lang.Object> Constant - multiply : java.lang.String ArgumentList - (le,re) for both lines 175 and 176, the accessedVariable for the Variable "compCtx" is org.codehaus.gro
more help with an AST
Hello All, Let me go to the well one more time for help with my AST First, let me ask --- is there any reason the AST browser would lie and show you what you want to see and not what the compiler really does?? Sorry, that's harsh. But, I've been staring that the AST browser for hours trying to spot the difference between two lines of code - one that runs and one the blows up - and I can't see any thing other than lineNumber/columnNumber differences. Some background. I want to replace some binary methods (like multiply and plus) so I can play around and do them the way I want. So, my AST goes through and replaces binary method calls like "le * re" with "myCtx.multiply( le, re)". Looking at the massaged code through the AST browser, it looks like my xform is doing what it should - but the code won't execute. Trying to get to a simple example, if I have two lines of code before xforming: sum = myCtx.multiply( le, re) <--- the xform leaves this alone sum = le * re <--- the xform changes this the browser shows a post-xform output of: sum = myCtx.multiply( le, re) <--- this executes sum = myCtx.multiply( le, re) <--- this doesn't But, when run, the first line works while the second one results in a MissingMethodException stating there is no "multiply" method for the type Complex - which is the type of "le". It's as if the compiler tried to execute "le * re" (which would give exactly this MME) and not "myCtx.multiply( le, re)". Drilling down in the AST itself, I'm not seeing any difference - other than line numbers and column numbers - between the various *Expressions (e.g. VariableExpression) making up the subtrees for the two lines. Obviously I'm doing something wrong. But I can't see what it is. Any suggestions? Regards, Ed Clark
Re: help with an AST
Just in case someone searches this topic in the future (probably me in a year or two ;) ), using ASSIGN rather than ASSIGNMENT_OPERATOR does work. Thanks Paul. On 02/22/2017 06:07 PM, Paul King wrote: You can probably use ASSIGN rather than ASSIGNMENT_OPERATOR which is meant to be a type class though I am not sure we really use it. On Thu, Feb 23, 2017 at 2:08 AM, Ed Clark <eacl...@ameritech.net> wrote: I can report progress. Turns out there were two problems. The error message that I was getting concerning : "=" not being supported had to do with how I built the token for the BinaryExpression. I was using: new BinaryExpression( sV,// a VariableExpression new Token( Types.ASSIGNMENT_OPERATOR, '=', -1, -1), rtV// another VariableExpression When I examined the AST that was generated after the transform, I noticed that the corresponding token mentioned: . But, if I looked at a separate AST from hand written code that matched the output of the transform, that token mentioned: symbol "=". Not the same After a quick Google search I hit upon: new BinaryExpression( sV,// a VariableExpression Token.newSymbol( '=', -1, -1), rtV// another VariableExpression This gets rid of the error! I'm not sure why the first way to build a Token doesn't work. I'll also note that there are a number code examples using the first approach that turn up in a web search. In any case, I'm happy to have one that does work. At this point, applying the VariableScopeVisitor that Paul suggested seems to clean up my remaining problem with scoping issues. Yeah! On to the next wall, how to generate a table of method signatures (at transform time) for all the methods defined in the user written classes (marked with my annotation)... Many thanks, Ed On 02/20/2017 12:06 PM, Ed Clark wrote: Ok, poking around the source for VariableScopeVisitor didn't provide me with any insights. It did lead me to try VariableScopeVisitor scopeVisitor = new VariableScopeVisitor( source, true) but I still get the error: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported One possible twist that I noticed, is if I run my test script under groovyConsole I get one error message. But, if I run the equivalent code (with a 'main') as a standalone groovy file, the error message is printed twice. Not sure what that indicates. But, it is tied to my inserted statements. If I comment out the statement insertions, the compiler is happy. So I'm guessing I'm building bad statements. What is the proper way to build a statement that set a property that is defined in a base class (i.e., extended by a class that gets instantiated)? I'm currently doing: VariableExpression cV = new VariableExpression( '__currentContext') //PropertyExpression cP = new PropertyExpression( cnStack[ -1], '__currentContext') ExpressionStatement currStmt = new ExpressionStatement( new BinaryExpression( cV, // also tried assigning to cP instead of cV new Token(Types.ASSIGNMENT_OPERATOR, "=", -1, -1), cnStack[ -1] // new MethodCallExpression( VariableExpression.THIS_EXPRESSION, // new ConstantExpression( 'getDelegate'), // new ArgumentListExpress()) ) ) blockStatement.statements.add( 0, currStmt) (I've tried with and without the VariableScopeVisitor call, and with and without a call to "blockStatement.variableScope.putReferencedClassVariable( cv)".) So, does this look like the correct way to set the value of a property that is inherited from a base class? (The somewhat frustrating thing is the resultant AST with the inserted statements looks correct after the transform (up through the Instruction Selection phase). In fact, if I type that code into a separate groovyConsole, it runs.) Thanks for your time, Ed On 02/16/2017 04:41 PM, Paul King wrote: Do you have something like: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source) scopeVisitor.visitClass(cNode) for each of your closure(s)? Where cNode is a closure's classNode? Cheers, Paul.
Re: help with an AST
I can report progress. Turns out there were two problems. The error message that I was getting concerning : "=" not being supported had to do with how I built the token for the BinaryExpression. I was using: new BinaryExpression( sV,// a VariableExpression new Token( Types.ASSIGNMENT_OPERATOR, '=', -1, -1), rtV// another VariableExpression When I examined the AST that was generated after the transform, I noticed that the corresponding token mentioned: . But, if I looked at a separate AST from hand written code that matched the output of the transform, that token mentioned: symbol "=". Not the same After a quick Google search I hit upon: new BinaryExpression( sV,// a VariableExpression Token.newSymbol( '=', -1, -1), rtV// another VariableExpression This gets rid of the error! I'm not sure why the first way to build a Token doesn't work. I'll also note that there are a number code examples using the first approach that turn up in a web search. In any case, I'm happy to have one that does work. At this point, applying the VariableScopeVisitor that Paul suggested seems to clean up my remaining problem with scoping issues. Yeah! On to the next wall, how to generate a table of method signatures (at transform time) for all the methods defined in the user written classes (marked with my annotation)... Many thanks, Ed On 02/20/2017 12:06 PM, Ed Clark wrote: Ok, poking around the source for VariableScopeVisitor didn't provide me with any insights. It did lead me to try VariableScopeVisitor scopeVisitor = new VariableScopeVisitor( source, true) but I still get the error: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported One possible twist that I noticed, is if I run my test script under groovyConsole I get one error message. But, if I run the equivalent code (with a 'main') as a standalone groovy file, the error message is printed twice. Not sure what that indicates. But, it is tied to my inserted statements. If I comment out the statement insertions, the compiler is happy. So I'm guessing I'm building bad statements. What is the proper way to build a statement that set a property that is defined in a base class (i.e., extended by a class that gets instantiated)? I'm currently doing: VariableExpression cV = newVariableExpression( '__currentContext') //PropertyExpression cP = newPropertyExpression( cnStack[ -1], '__currentContext') ExpressionStatement currStmt = newExpressionStatement( new BinaryExpression( cV, // also tried assigning to cP instead of cV new Token(Types.ASSIGNMENT_OPERATOR, "=", -1, -1), cnStack[ -1] // new MethodCallExpression( VariableExpression.THIS_EXPRESSION, // new ConstantExpression( 'getDelegate'), // new ArgumentListExpress()) ) ) blockStatement.statements.add( 0, currStmt) (I've tried with and without the VariableScopeVisitor call, and with and without a call to "blockStatement.variableScope.putReferencedClassVariable( cv)".) So, does this look like the correct way to set the value of a property that is inherited from a base class? (The somewhat frustrating thing is the resultant AST with the inserted statements looks correct after the transform (up through the Instruction Selection phase). In fact, if I type that code into a separate groovyConsole, it runs.) Thanks for your time, Ed On 02/16/2017 04:41 PM, Paul King wrote: Do you have something like: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source) scopeVisitor.visitClass(cNode) for each of your closure(s)? Where cNode is a closure's classNode? Cheers, Paul.
Re: help with an AST
Ok, poking around the source for VariableScopeVisitor didn't provide me with any insights. It did lead me to try VariableScopeVisitor scopeVisitor = new VariableScopeVisitor( source, true) but I still get the error: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported One possible twist that I noticed, is if I run my test script under groovyConsole I get one error message. But, if I run the equivalent code (with a 'main') as a standalone groovy file, the error message is printed twice. Not sure what that indicates. But, it is tied to my inserted statements. If I comment out the statement insertions, the compiler is happy. So I'm guessing I'm building bad statements. What is the proper way to build a statement that set a property that is defined in a base class (i.e., extended by a class that gets instantiated)? I'm currently doing: VariableExpression cV = newVariableExpression( '__currentContext') //PropertyExpression cP = newPropertyExpression( cnStack[ -1], '__currentContext') ExpressionStatement currStmt = newExpressionStatement( new BinaryExpression( cV, // also tried assigning to cP instead of cV new Token(Types.ASSIGNMENT_OPERATOR, "=", -1, -1), cnStack[ -1] // new MethodCallExpression( VariableExpression.THIS_EXPRESSION, // new ConstantExpression( 'getDelegate'), // new ArgumentListExpress()) ) ) blockStatement.statements.add( 0, currStmt) (I've tried with and without the VariableScopeVisitor call, and with and without a call to "blockStatement.variableScope.putReferencedClassVariable( cv)".) So, does this look like the correct way to set the value of a property that is inherited from a base class? (The somewhat frustrating thing is the resultant AST with the inserted statements looks correct after the transform (up through the Instruction Selection phase). In fact, if I type that code into a separate groovyConsole, it runs.) Thanks for your time, Ed On 02/16/2017 04:41 PM, Paul King wrote: Do you have something like: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source) scopeVisitor.visitClass(cNode) for each of your closure(s)? Where cNode is a closure's classNode? Cheers, Paul.
Re: help with an AST
Hi Paul, Unfortunately that didn't help. I still get the error: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported I put those two lines right after my top level "visit" call. Thinking about it, the class node being visited is that of the top level script - the classes that are being transformed are not explicitly being visited. Perhaps the "visit" at the top level script will descend into the inner classes? On the off chance that it won't, I also tried something I found online: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor( sourceUnit) sourceUnit.AST.classes.each { println '1 visiting class ' + it scopeVisitor.visitClass( it) } (Obviously, the println is there to check that the xformed classes are visited explicitly; which they are.) The error is still there. I also saw warnings online that you don't want to visit the same scope twice. If a visit to the top level script implicitly visits the classes defined within, then this would be a double visit to the xformed classes - I'm guessing. (Perhaps I need to look at the VariableScopeVisitor implementation to better understand what's going on.) Other thoughts/suggestions? Regards, Ed On 02/16/2017 04:41 PM, Paul King wrote: Do you have something like: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source) scopeVisitor.visitClass(cNode) for each of your closure(s)? Where cNode is a closure's classNode? Cheers, Paul. On Thu, Feb 16, 2017 at 9:35 PM, Ed Clark <eacl...@ameritech.net> wrote: Ok, a little more headbanging and I seem to have gotten farther (maybe?). At least the error message has changed. Now I'm getting: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported Searching hasn't helped with this one. The xform-ed code looks good -- in fact, if I type the code into a separate groovyConsole, it will run. (The console AST generation works up thru the Instruction Selection phase, obviously.) I'm guessing it's still with how I'm setting up the scoping (or how I'm not setting up the scoping). Ideas, please? Thanks, Ed On 02/14/2017 12:58 PM, Ed Clark wrote: On 02/14/2017 12:16 PM, Jochen Theodorou wrote: On 14.02.2017 12:41, Ed Clark wrote: Hi Jochen, Well, I've been slowly making progress on this; kind of feels like bashing my head against a wall at times, but I have made a small hole in the wall through which I can see my goal. ;-) making holes my lead to brain damage.. then things get really hard to solve ;) Maybe I'm too late, and that's why things aren't coming together ;) [...] Specifically, I haven't figured out how to inject a variable into the scope of an outer with's closure that can be used by code in an interior with's closure. For example, consider myCtx1.with { __outerCtx1 = null// injected statement __currCtx1 = myCtx1 // injected statement some code ... myCtx2.with { __outerCtx2 = __currCtx1 // injected statement <--- doesn't work __currCtx2 = myCtx2 // injected statement where is __currCtx1 and __outerCtx1 coming from? Are they supposed to be new local variables? in that case you will have to add a DeclarationStatement, not just an assignment to a VariableExpression. Otherwise the compiler will thnk they are dynamic properties and tries to resolve them against the context. as for the logic behind __outerCtxN... with number wouldn't have to be null I would have said you should think of using getOwner on Closure Hmmm, I'm close to that, but not quite the same. I was trying ExpressionStatement currCtx = new ExpressionStatement( new DeclarationExpression ( new VariableExpression( "__currCtx$levelcnt"), new Token( Types.ASSIGNMENT_OPERATOR, "=", -1, -1), new MethodCallExpression( new VariableExpression( 'this'), 'getDelegate', new ArgumentListExpression()) ) ) Would a DeclarationStatment act differently from an ExpressionStatement with an embedded DeclarationExpression? If my foggy memory is correct, I wrote my code after looking at the AST displayed for a short test script in groovyConsole. Plus, if foggy memory serves, I tried using getOwner and it came back with the closure being owned by the test script, not the object doing the with. Calling getDelegate gave me the object. If foggy memory serves. I also tried playing around with setClosureSharedVariable( true) and putReferencedLocalVariable() without success. But, those were somewhat blind stabs in the dark, so I might not have been using them correctly. Looking at the AST generated by groovyConsole, my transform looks like it is working, but the compiler complains about things not being in scope (in the inner closure). So, I'm doing something wrong with setting up the scoping. bye Jochen Thanks, Ed
Re: help with an AST
Hi Paul, No I don't have that. Let me play around with it. Thanks for the pointer. Ed On 02/16/2017 04:41 PM, Paul King wrote: Do you have something like: VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source) scopeVisitor.visitClass(cNode) for each of your closure(s)? Where cNode is a closure's classNode? Cheers, Paul. On Thu, Feb 16, 2017 at 9:35 PM, Ed Clark <eacl...@ameritech.net> wrote: Ok, a little more headbanging and I seem to have gotten farther (maybe?). At least the error message has changed. Now I'm getting: BUG! exception in phase 'class generation' in source unit 'CtxTest2.groovy' Operation: (: "=" ) not supported Searching hasn't helped with this one. The xform-ed code looks good -- in fact, if I type the code into a separate groovyConsole, it will run. (The console AST generation works up thru the Instruction Selection phase, obviously.) I'm guessing it's still with how I'm setting up the scoping (or how I'm not setting up the scoping). Ideas, please? Thanks, Ed On 02/14/2017 12:58 PM, Ed Clark wrote: On 02/14/2017 12:16 PM, Jochen Theodorou wrote: On 14.02.2017 12:41, Ed Clark wrote: Hi Jochen, Well, I've been slowly making progress on this; kind of feels like bashing my head against a wall at times, but I have made a small hole in the wall through which I can see my goal. ;-) making holes my lead to brain damage.. then things get really hard to solve ;) Maybe I'm too late, and that's why things aren't coming together ;) [...] Specifically, I haven't figured out how to inject a variable into the scope of an outer with's closure that can be used by code in an interior with's closure. For example, consider myCtx1.with { __outerCtx1 = null// injected statement __currCtx1 = myCtx1 // injected statement some code ... myCtx2.with { __outerCtx2 = __currCtx1 // injected statement <--- doesn't work __currCtx2 = myCtx2 // injected statement where is __currCtx1 and __outerCtx1 coming from? Are they supposed to be new local variables? in that case you will have to add a DeclarationStatement, not just an assignment to a VariableExpression. Otherwise the compiler will thnk they are dynamic properties and tries to resolve them against the context. as for the logic behind __outerCtxN... with number wouldn't have to be null I would have said you should think of using getOwner on Closure Hmmm, I'm close to that, but not quite the same. I was trying ExpressionStatement currCtx = new ExpressionStatement( new DeclarationExpression ( new VariableExpression( "__currCtx$levelcnt"), new Token( Types.ASSIGNMENT_OPERATOR, "=", -1, -1), new MethodCallExpression( new VariableExpression( 'this'), 'getDelegate', new ArgumentListExpression()) ) ) Would a DeclarationStatment act differently from an ExpressionStatement with an embedded DeclarationExpression? If my foggy memory is correct, I wrote my code after looking at the AST displayed for a short test script in groovyConsole. Plus, if foggy memory serves, I tried using getOwner and it came back with the closure being owned by the test script, not the object doing the with. Calling getDelegate gave me the object. If foggy memory serves. I also tried playing around with setClosureSharedVariable( true) and putReferencedLocalVariable() without success. But, those were somewhat blind stabs in the dark, so I might not have been using them correctly. Looking at the AST generated by groovyConsole, my transform looks like it is working, but the compiler complains about things not being in scope (in the inner closure). So, I'm doing something wrong with setting up the scoping. bye Jochen Thanks, Ed
Re: help with an AST
On 02/14/2017 12:16 PM, Jochen Theodorou wrote: On 14.02.2017 12:41, Ed Clark wrote: Hi Jochen, Well, I've been slowly making progress on this; kind of feels like bashing my head against a wall at times, but I have made a small hole in the wall through which I can see my goal. ;-) making holes my lead to brain damage.. then things get really hard to solve ;) Maybe I'm too late, and that's why things aren't coming together ;) [...] Specifically, I haven't figured out how to inject a variable into the scope of an outer with's closure that can be used by code in an interior with's closure. For example, consider myCtx1.with { __outerCtx1 = null// injected statement __currCtx1 = myCtx1 // injected statement some code ... myCtx2.with { __outerCtx2 = __currCtx1 // injected statement <--- doesn't work __currCtx2 = myCtx2 // injected statement where is __currCtx1 and __outerCtx1 coming from? Are they supposed to be new local variables? in that case you will have to add a DeclarationStatement, not just an assignment to a VariableExpression. Otherwise the compiler will thnk they are dynamic properties and tries to resolve them against the context. as for the logic behind __outerCtxN... with number wouldn't have to be null I would have said you should think of using getOwner on Closure Hmmm, I'm close to that, but not quite the same. I was trying ExpressionStatement currCtx = new ExpressionStatement( new DeclarationExpression ( new VariableExpression( "__currCtx$levelcnt"), new Token( Types.ASSIGNMENT_OPERATOR, "=", -1, -1), new MethodCallExpression( new VariableExpression( 'this'), 'getDelegate', new ArgumentListExpression()) ) ) Would a DeclarationStatment act differently from an ExpressionStatement with an embedded DeclarationExpression? If my foggy memory is correct, I wrote my code after looking at the AST displayed for a short test script in groovyConsole. Plus, if foggy memory serves, I tried using getOwner and it came back with the closure being owned by the test script, not the object doing the with. Calling getDelegate gave me the object. If foggy memory serves. I also tried playing around with setClosureSharedVariable( true) and putReferencedLocalVariable() without success. But, those were somewhat blind stabs in the dark, so I might not have been using them correctly. Looking at the AST generated by groovyConsole, my transform looks like it is working, but the compiler complains about things not being in scope (in the inner closure). So, I'm doing something wrong with setting up the scoping. bye Jochen Thanks, Ed
Re: help with an AST
Hi Jochen, Well, I've been slowly making progress on this; kind of feels like bashing my head against a wall at times, but I have made a small hole in the wall through which I can see my goal. ;-) Unfortunately, I've reached a point where the hole isn't getting any bigger and my google-fu isn't up to the task of finding what I need to make it bigger. Specifically, I haven't figured out how to inject a variable into the scope of an outer with's closure that can be used by code in an interior with's closure. For example, consider myCtx1.with { __outerCtx1 = null// injected statement __currCtx1 = myCtx1 // injected statement some code ... myCtx2.with { __outerCtx2 = __currCtx1 // injected statement <--- doesn't work __currCtx2 = myCtx2 // injected statement My problem is the compiler chokes on the reference to __currCtx1 in the inner with closure, claiming that __currCtx1 isn't a property of myCtx1. My google-fu only tells me I haven't set up the scoping correctly, but for the life of me I haven't found the correct way to do this. And further experimenting, groping in the dark, and head banging hasn't helped either. :\ Any illuminating insight, or direction pointing, or example would be greatly appreciated! Thanks Ed On 12/31/2016 06:36 PM, Jochen Theodorou wrote: On 31.12.2016 17:32, Ed Clark wrote: [...] Assuming you still want to do something like this with more... AST involvement... My questions for you are, - is an AST the way to go? first you have to decide what you want to compile to and then we can think about how the AST for that has to look like. So this is actually the last step. But assuming you have some kind of handler object you could compile a+b to handler.invoke("plus",a,b)... in other words you would replace almost any expression by a MethodCallExpression. Hint: ExpressonTransformer and helper classes. Hmmm, I will have a handler object - sort of - and that's the context object itself. Well, at least in the case of instance based contexts. For class based contexts, there won't be an instantiated handler, but I could still see having a static "invoke" method. I hadn't considered the invoke approach; it is interesting. I think it would provide some additional flexibility that the context developer could use to add "operators" beyond the ones built into the Groovy parser/AST. I'll have to think about this some more. the handler object does not have to be the context object itself. It can be a collection of context objects, be it classes or instances. It could be also be a collection of methods and instances from the context. Important for the compiler part is only the calling convention. - I'm guessing that I can do the context nesting and composing by building on methodMissing (with ctx2 chaining to ctx3 chaining to Ctx1 above), but is there a better way? I guess the code path for categories won´t help you here, since that is kind of special treated. You could create a special meta class and all the context methods to it, then use its mechanisms to select an appropriate method... hint getMetaMethod, init Just to be clear, I don't think there is anything special about the contexts - they are just POGOs. Their methods just happen to be focused on manipulating objects that fall under their scope. So, I'm not sure how creating a meta class would help. you would not really create a meta class of a specific class, you would create a meta class in the sense of an enumeration of methods and method selection mechanism. But well... now need for that at this point I guess. You can of course simply work with methodMissing. [...] Yeah, one of my problems is I think too far ahead ;). I start worrying about what it might take to run a marathon when I haven't even learned to walk. So I don't even get started. Part of the this resolution is to just get off my butt and write some code. that's a good resolution for the new year ;) Let me help you: assuming you use "with"-blocks: Step 1) write an AST transformation that will recognize the with-block and store the context in a variable Step 2) add an expression transformer, that will transform all the expressions of interest in the with-block to method calls based on the context variable Step 3) implement a context Step 4) transform nested with method calls to calls that allow you the creation and nesting of a context plus add code to delegate to outer contexts Even if it turns out not to be useful in the end (and I think it will be useful) you will still get some practice about writing such things. Nothing to really loose here imho ;) bye Jochen
Re: problem with GroovyLab startup at some platforms?
On 01/19/2017 08:44 AM, sterg wrote: On 01/19/2017 03:39 PM, Jochen Theodorou wrote: On 19.01.2017 12:57, sterg wrote: Hi all, a user reported me, that GroovyLab (https://github.com/sterglee/GroovyLab) fails silently at startup, at his platform. no error at all? yes, with no error message, or e.g. a stack trace of a possible exception fault. However, up to now I couldn't reproducible the fault. bye Jochen Thanks Stergios Since I am the reader in question, let me add some info. The snapshot that I grabbed in November works fine. When I grabbed a new snapshot a couple of days ago I noticed that the startup script just returned without anything happening. And, if I just use the command "java -jar GroovyLab.jar", the November one starts but the January one dies silently. (Eyeballing it, the January command returns after roughly the same length of time that the first window takes to appear on the November one, about 1 sec on my machine.) More info - the January snapshot dies on both my Fedora 24 main machine and a Centos 7 machine I've got on the side. But, it runs fine on a RaspberryPi3 that I've got. So, score one hit for Raspbian, and 2 misses for Redhat. On the F24 machine java -version gives: java version "1.8.0_72" Java(TM) SE Runtime Environment (build 1.8.0_72-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode) On the Centos7 machine java -version gives: openjdk version "1.8.0_111" OpenJDK Runtime Environment (build 1.8.0_111-b15) OpenJDK 64-Bit Server VM (build 25.111-b15, mixed mode) On the Raspbian machine java -version gives: java version "1.8.0_65" Java(TM) SE Runtime Environment (build 1.8.0_65-b17) Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode) Ed
help with an AST
Happy New Year All! As one of my New Year's resolutions, I'm going to try and implement a programming construct that I've been want to play with for a while - and I think a Groovy AST just might let me do it. While the syntax part of this is straightforward (I think), I'm not as clear on the how of the method resolution logic that will be at the core. The basic idea is that I'll be able to designate a section of code where binary operators would be resolved not against the neighbouring object's class, but against the surrounding context. Perhaps some code will make my goal clearer My understanding of Groovy (and OO in general) is that an expression like obj1 + obj2 is interpreted as if it were written obj1.plus( obj2) What I'd like to do is have something like withCtx( ctx1) { obj1 + obj2 } get interpreted as ctx1.plus( obj1, obj2) If I squint at this, it kind of sort of looks to me a bit like how the "with" construct in Groovy works. But, the with construct is an enhancement to the existing OO method resolution; this construct would go in a different direction. (Actually, to be useful, the interior expression would probably be something like -- var1 = obj1 + obj2 -- but I want to focus on one step/method at a time.) With this idea, methods between objects (e.g. binary methods) don't belong to the class of (one of the) objects involved, but to the context within which the objects are being used. And, just to make things more challenging, I'd like to be able to nest and compose contexts. Consider withCtx( Ctx1) { withCtx( ctx2, ctx3) { obj1 + obj2 } } Here, the methods of ctx2 would be checked to see if there's a "plus" that can take arguments obj1 and obj2. If not, then ctx3's methods will be check. If there's no appropriate "plus" in ctx3, then Ctx1's methods will be checked. Finally, if there are no appropriate context methods for "plus-ing" these two objects, then method resolution would fall back to the normal Groovy approach. To add yet another wrinkle, I'd like to be able to use either a Context class or a context instance when doing this. So, in the above, if "Ctx1" is a class name (note the cap C), its static methods would be used. But, assuming ctx2 and ctx3 are context instances (note the lower case c's), the appropriate instance methods would be used. Hopefully this description makes my goal clearer. My questions for you are, - is an AST the way to go? - I'm guessing that I can do the context nesting and composing by building on methodMissing (with ctx2 chaining to ctx3 chaining to Ctx1 above), but is there a better way? - what might I be breaking in Groovy by doing this? - what help/hints can I get from the compiler vs. doing this all at runtime? Thanks for your time, Ed Clark