http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java new file mode 100644 index 0000000..7c06e69 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.Expression; + + +/** + * Represents a case statement in a switch statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class CaseStatement extends Statement { + + private Statement code; + private Expression expression; + + public CaseStatement(Expression expression, Statement code) { + this.expression = expression; + this.code = code; + } + + public Statement getCode() { + return code; + } + + public void setCode(Statement code) { + this.code = code; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression e) { + expression=e; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitCaseStatement(this); + } + + public String toString() { + return super.toString() + "[expression: " + expression + "; code: " + code + "]"; + } +}
http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java new file mode 100644 index 0000000..3f40957 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.Parameter; + + +/** + * Represents a catch (Exception var) { } statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class CatchStatement extends Statement { + + private Parameter variable; + + private Statement code; + + public CatchStatement(Parameter variable, Statement code) { + this.variable = variable; + this.code = code; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitCatchStatement(this); + } + + public Statement getCode() { + return code; + } + + public ClassNode getExceptionType() { + return variable.getType(); + } + + public Parameter getVariable() { + return variable; + } + + public void setCode(Statement code) { + this.code = code; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java new file mode 100644 index 0000000..034dcf2 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; + + +/** + * Represents a continue statement in a loop statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class ContinueStatement extends Statement { + + private String label; + + public ContinueStatement() { + this(null); + } + + public ContinueStatement(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitContinueStatement(this); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java new file mode 100644 index 0000000..a7b518b --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.BooleanExpression; + +/** + * Represents a do { ... } while (condition) loop in Groovy + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class DoWhileStatement extends Statement implements LoopingStatement { + + private BooleanExpression booleanExpression; + private Statement loopBlock; + + + public DoWhileStatement(BooleanExpression booleanExpression, Statement loopBlock) { + this.booleanExpression = booleanExpression; + this.loopBlock = loopBlock; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitDoWhileLoop(this); + } + + public BooleanExpression getBooleanExpression() { + return booleanExpression; + } + + public Statement getLoopBlock() { + return loopBlock; + } + public void setBooleanExpression(BooleanExpression booleanExpression) { + this.booleanExpression = booleanExpression; + } + + public void setLoopBlock(Statement loopBlock) { + this.loopBlock = loopBlock; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java new file mode 100644 index 0000000..d4b706c --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; + +/** + * Represents an empty statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class EmptyStatement extends Statement { + + public static final EmptyStatement INSTANCE = new EmptyStatement(); + + public void visit(GroovyCodeVisitor visitor) { + } + + public boolean isEmpty() { + return true; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java new file mode 100644 index 0000000..c6376b2 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.Expression; + + +/** + * A simple statement such as a method call where the return value is ignored + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class ExpressionStatement extends Statement { + + private Expression expression; + + public ExpressionStatement(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException("expression cannot be null"); + } + this.expression = expression; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitExpressionStatement(this); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public String getText() { + return expression.getText(); + } + + public String toString() { + return super.toString() + "[expression:" + expression + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java new file mode 100644 index 0000000..072ee6e --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.Parameter; +import org.codehaus.groovy.ast.VariableScope; +import org.codehaus.groovy.ast.expr.Expression; + +/** + * Represents a standard for loop in Groovy + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class ForStatement extends Statement implements LoopingStatement { + public static final Parameter FOR_LOOP_DUMMY = new Parameter(ClassHelper.OBJECT_TYPE,"forLoopDummyParameter"); + + private Parameter variable; + private Expression collectionExpression; + private Statement loopBlock; + private VariableScope scope; + + + public ForStatement(Parameter variable, Expression collectionExpression, Statement loopBlock) { + this.variable = variable; + this.collectionExpression = collectionExpression; + this.loopBlock = loopBlock; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitForLoop(this); + } + + public Expression getCollectionExpression() { + return collectionExpression; + } + + public Statement getLoopBlock() { + return loopBlock; + } + + public Parameter getVariable() { + return variable; + } + + public ClassNode getVariableType() { + return variable.getType(); + } + + public void setCollectionExpression(Expression collectionExpression) { + this.collectionExpression = collectionExpression; + } + + public void setVariableScope(VariableScope variableScope) { + scope = variableScope; + } + + public VariableScope getVariableScope() { + return scope; + } + + public void setLoopBlock(Statement loopBlock) { + this.loopBlock = loopBlock; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java new file mode 100644 index 0000000..3f614cc --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.BooleanExpression; + +/** + * Represents an if (condition) { ... } else { ... } statement in Groovy + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class IfStatement extends Statement { + + private BooleanExpression booleanExpression; + private Statement ifBlock; + private Statement elseBlock; + + + public IfStatement(BooleanExpression booleanExpression, Statement ifBlock, Statement elseBlock) { + this.booleanExpression = booleanExpression; + this.ifBlock = ifBlock; + this.elseBlock = elseBlock; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitIfElse(this); + } + + public BooleanExpression getBooleanExpression() { + return booleanExpression; + } + + public Statement getIfBlock() { + return ifBlock; + } + + public Statement getElseBlock() { + return elseBlock; + } + + public void setBooleanExpression(BooleanExpression booleanExpression) { + this.booleanExpression = booleanExpression; + } + + public void setIfBlock(Statement statement) { + ifBlock = statement; + } + + public void setElseBlock(Statement statement) { + elseBlock = statement; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java new file mode 100644 index 0000000..4568103 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +/** +* This is an AST Node that provides some sort of looping mechanism. Typically +* in the form of a block that will be executed repeatedly. +* DoWhileStatements, WhileStatements, and ForStatements are all examples of LoopingStatements. +* +* @author Hamlet D'Arcy +*/ +public interface LoopingStatement { + + /** + * Gets the loop block. + */ + Statement getLoopBlock(); + /** + * Sets the loop block. + */ + void setLoopBlock(Statement loopBlock); +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java new file mode 100644 index 0000000..9e08ebd --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.ConstantExpression; +import org.codehaus.groovy.ast.expr.Expression; + +/** + * A return statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class ReturnStatement extends Statement { + /** + * Only used for synthetic return statements emitted by the compiler. + * For comparisons use isReturningNullOrVoid() instead. + */ + public static final ReturnStatement RETURN_NULL_OR_VOID = new ReturnStatement(ConstantExpression.NULL); + + private Expression expression; + + public ReturnStatement(ExpressionStatement statement) { + this(statement.getExpression()); + setStatementLabel(statement.getStatementLabel()); + } + + public ReturnStatement(Expression expression) { + this.expression = expression; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitReturnStatement(this); + } + + public Expression getExpression() { + return expression; + } + + public String getText() { + return "return " + expression.getText(); + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public boolean isReturningNullOrVoid() { + return expression instanceof ConstantExpression + && ((ConstantExpression)expression).isNullExpression(); + } + + public String toString() { + return super.toString() + "[expression:" + expression + "]"; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java new file mode 100644 index 0000000..80dbc4d --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.ASTNode; + +import java.util.LinkedList; +import java.util.List; + +/** + * Base class for any statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class Statement extends ASTNode { + + private List<String> statementLabels; + + public Statement() { + statementLabels = null; + } + + public List<String> getStatementLabels() { + return statementLabels; + } + + // TODO @Deprecated + public String getStatementLabel() { + // last label by default which is added first by APP + return statementLabels == null ? null : statementLabels.get(0); + } + + // TODO @Deprecated + public void setStatementLabel(String label) { + if (statementLabels == null) statementLabels = new LinkedList<String>(); + statementLabels.add(label); + } + + public void addStatementLabel(String label) { + if (statementLabels == null) statementLabels = new LinkedList<String>(); + statementLabels.add(label); + } + + public boolean isEmpty() { + return false; + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java new file mode 100644 index 0000000..bad0194 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.Expression; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a switch (object) { case value: ... case [1, 2, 3]: ... default: ... } statement in Groovy. + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class SwitchStatement extends Statement { + + private Expression expression; + private List<CaseStatement> caseStatements = new ArrayList<CaseStatement>(); + private Statement defaultStatement; + + + public SwitchStatement(Expression expression) { + this(expression, EmptyStatement.INSTANCE); + } + + public SwitchStatement(Expression expression, Statement defaultStatement) { + this.expression = expression; + this.defaultStatement = defaultStatement; + } + + public SwitchStatement(Expression expression, List<CaseStatement> caseStatements, Statement defaultStatement) { + this.expression = expression; + this.caseStatements = caseStatements; + this.defaultStatement = defaultStatement; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitSwitch(this); + } + + public List<CaseStatement> getCaseStatements() { + return caseStatements; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression e) { + expression=e; + } + + public Statement getDefaultStatement() { + return defaultStatement; + } + + public void setDefaultStatement(Statement defaultStatement) { + this.defaultStatement = defaultStatement; + } + + public void addCase(CaseStatement caseStatement) { + caseStatements.add(caseStatement); + } + + /** + * @return the case statement of the given index or null + */ + public CaseStatement getCaseStatement(int idx) { + if (idx >= 0 && idx < caseStatements.size()) { + return caseStatements.get(idx); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java new file mode 100644 index 0000000..1fd3e5c --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.Expression; + + +/** + * Represents a synchronized statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class SynchronizedStatement extends Statement { + + private Statement code; + private Expression expression; + + public SynchronizedStatement(Expression expression, Statement code) { + this.expression = expression; + this.code = code; + } + + public Statement getCode() { + return code; + } + + public void setCode(Statement statement) { + code = statement; + } + + public Expression getExpression() { + return expression; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitSynchronizedStatement(this); + } + public void setExpression(Expression expression) { + this.expression = expression; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java new file mode 100644 index 0000000..a217840 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.Expression; + + +/** + * Represents a throw statement + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class ThrowStatement extends Statement { + + private Expression expression; + + public ThrowStatement(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitThrowStatement(this); + } + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String getText() { + return "throw " + expression.getText(); + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java new file mode 100644 index 0000000..172e403 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a try { ... } catch () finally {} statement in Groovy + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class TryCatchStatement extends Statement { + + private Statement tryStatement; + private List<CatchStatement> catchStatements = new ArrayList<CatchStatement>(); + private Statement finallyStatement; + + + public TryCatchStatement(Statement tryStatement, Statement finallyStatement) { + this.tryStatement = tryStatement; + this.finallyStatement = finallyStatement; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitTryCatchFinally(this); + } + + public List<CatchStatement> getCatchStatements() { + return catchStatements; + } + + public Statement getFinallyStatement() { + return finallyStatement; + } + + public Statement getTryStatement() { + return tryStatement; + } + + public void addCatch(CatchStatement catchStatement) { + catchStatements.add(catchStatement); + } + + /** + * @return the catch statement of the given index or null + */ + public CatchStatement getCatchStatement(int idx) { + if (idx >= 0 && idx < catchStatements.size()) { + return catchStatements.get(idx); + } + return null; + } + + public void setTryStatement(Statement tryStatement) { + this.tryStatement = tryStatement; + } + + public void setCatchStatement(int idx, CatchStatement catchStatement) { + catchStatements.set(idx, catchStatement); + } + + public void setFinallyStatement(Statement finallyStatement) { + this.finallyStatement = finallyStatement; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java new file mode 100644 index 0000000..e325481 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.stmt; + +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.BooleanExpression; + +/** + * Represents a while (condition) { ... } loop in Groovy + * + * @author <a href="mailto:[email protected]">James Strachan</a> + */ +public class WhileStatement extends Statement implements LoopingStatement { + + private BooleanExpression booleanExpression; + private Statement loopBlock; + + + public WhileStatement(BooleanExpression booleanExpression, Statement loopBlock) { + this.booleanExpression = booleanExpression; + this.loopBlock = loopBlock; + } + + public void visit(GroovyCodeVisitor visitor) { + visitor.visitWhileLoop(this); + } + + public BooleanExpression getBooleanExpression() { + return booleanExpression; + } + + public Statement getLoopBlock() { + return loopBlock; + } + + public void setBooleanExpression(BooleanExpression booleanExpression) { + this.booleanExpression = booleanExpression; + } + + public void setLoopBlock(Statement loopBlock) { + this.loopBlock = loopBlock; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/package.html ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/package.html b/src/main/java/org/codehaus/groovy/ast/stmt/package.html new file mode 100644 index 0000000..8226776 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/stmt/package.html @@ -0,0 +1,28 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +--> +<html> + <head> + <title>package org.codehaus.groovy.ast.stmt.*</title> + </head> + <body> + <p>AST nodes for Groovy statements</p> + </body> +</html> http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java new file mode 100644 index 0000000..32d4a81 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.tools; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.PropertyNode; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static java.beans.Introspector.decapitalize; + +public class BeanUtils { + static final String GET_PREFIX = "get"; + static final String IS_PREFIX = "is"; + + /** + * Get all properties including JavaBean pseudo properties matching getter conventions. + * + * @param type the ClassNode + * @param includeSuperProperties whether to include super properties + * @param includeStatic whether to include static properties + * @param includePseudoGetters whether to include JavaBean pseudo (getXXX/isYYY) properties with no corresponding field + * @return the list of found property nodes + */ + public static List<PropertyNode> getAllProperties(ClassNode type, boolean includeSuperProperties, boolean includeStatic, boolean includePseudoGetters) { + // TODO add generics support so this can be used for @EAHC + // TODO add an includePseudoSetters so this can be used for @TupleConstructor + ClassNode node = type; + List<PropertyNode> result = new ArrayList<PropertyNode>(); + Set<String> names = new HashSet<String>(); + while (node != null) { + addExplicitProperties(node, result, names, includeStatic); + if (!includeSuperProperties) break; + node = node.getSuperClass(); + } + addPseudoProperties(type, result, names, includeStatic, includePseudoGetters, includeSuperProperties); + return result; + } + + private static void addExplicitProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic) { + for (PropertyNode pNode : cNode.getProperties()) { + if (includeStatic || !pNode.isStatic()) { + if (!names.contains(pNode.getName())) { + result.add(pNode); + names.add(pNode.getName()); + } + } + } + } + + private static void addPseudoProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic, boolean includePseudoGetters, boolean includeSuperProperties) { + if (!includePseudoGetters) return; + List<MethodNode> methods = cNode.getAllDeclaredMethods(); + ClassNode node = cNode.getSuperClass(); + if (includeSuperProperties) { + while (node != null) { + for (MethodNode next : node.getAllDeclaredMethods()) { + if (!next.isPrivate()) { + methods.add(next); + } + } + node = node.getSuperClass(); + } + } + for (MethodNode mNode : methods) { + if (!includeStatic && mNode.isStatic()) continue; + String name = mNode.getName(); + if ((name.length() <= 3 && !name.startsWith(IS_PREFIX)) || name.equals("getClass") || name.equals("getMetaClass") || name.equals("getDeclaringClass")) { + // Optimization: skip invalid propertyNames + continue; + } + if (mNode.getDeclaringClass() != cNode && mNode.isPrivate()) { + // skip private super methods + continue; + } + int paramCount = mNode.getParameters().length; + ClassNode returnType = mNode.getReturnType(); + if (paramCount == 0) { + if (name.startsWith(GET_PREFIX)) { + // Simple getter + String propName = decapitalize(name.substring(3)); + if (!names.contains(propName)) { + result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null)); + names.add(propName); + } + } else { + if (name.startsWith(IS_PREFIX) && returnType.equals(ClassHelper.boolean_TYPE)) { + // boolean getter + String propName = decapitalize(name.substring(2)); + if (!names.contains(propName)) { + names.add(propName); + result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null)); + } + } + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java new file mode 100644 index 0000000..5c43586 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.codehaus.groovy.ast.tools; + +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.PropertyNode; +import org.codehaus.groovy.ast.expr.Expression; + +import java.util.Map; + +@Deprecated +public class ClassNodeUtils { + @Deprecated + public static void addInterfaceMethods(ClassNode cNode, Map<String, MethodNode> methodsMap) { + org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromInterfaces(cNode, methodsMap); + } + + @Deprecated + public static Map<String, MethodNode> getDeclaredMethodMapsFromInterfaces(ClassNode cNode) { + return org.apache.groovy.ast.tools.ClassNodeUtils.getDeclaredMethodsFromInterfaces(cNode); + } + + @Deprecated + public static void addDeclaredMethodMapsFromSuperInterfaces(ClassNode cNode, Map<String, MethodNode> methodsMap) { + org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromAllInterfaces(cNode, methodsMap); + } + + @Deprecated + public static boolean hasPossibleStaticMethod(ClassNode cNode, String name, Expression arguments, boolean trySpread) { + return org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticMethod(cNode, name, arguments, trySpread); + } + + @Deprecated + public static boolean hasPossibleStaticProperty(ClassNode cNode, String methodName) { + return org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticProperty(cNode, methodName); + } + + @Deprecated + public static String getPropNameForAccessor(String accessorName) { + return org.apache.groovy.ast.tools.ClassNodeUtils.getPropNameForAccessor(accessorName); + } + + @Deprecated + public static boolean isValidAccessorName(String accessorName) { + return org.apache.groovy.ast.tools.ClassNodeUtils.isValidAccessorName(accessorName); + } + + @Deprecated + public static boolean hasStaticProperty(ClassNode cNode, String propName) { + return org.apache.groovy.ast.tools.ClassNodeUtils.hasStaticProperty(cNode, propName); + } + + @Deprecated + public static PropertyNode getStaticProperty(ClassNode cNode, String propName) { + return org.apache.groovy.ast.tools.ClassNodeUtils.getStaticProperty(cNode, propName); + } + + @Deprecated + public static boolean isInnerClass(ClassNode cNode) { + return org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass(cNode); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java new file mode 100644 index 0000000..06d4995 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.tools; + +import groovy.lang.Closure; +import org.codehaus.groovy.ast.expr.ClosureExpression; +import org.codehaus.groovy.control.io.ReaderSource; +/** + * Handy methods when working with Closure AST data structures. + */ + +public class ClosureUtils { + + /** + * Converts a ClosureExpression into the String source. + * + * @param readerSource a source + * @param expression a closure. Can't be null + * @return the source the closure was created from + * @throws java.lang.IllegalArgumentException when expression is null + * @throws java.lang.Exception when closure can't be read from source + */ + public static String convertClosureToSource(ReaderSource readerSource, ClosureExpression expression) throws Exception { + String source = GeneralUtils.convertASTToSource(readerSource, expression); + if (!source.startsWith("{")) { + throw new Exception("Error converting ClosureExpression into source code. Closures must start with {. Found: " + source); + } + return source; + } + + /** + * Does the Closure have a single char-like (char or Character) argument. + * @param c a Closure + * @return true if it has exactly one argument and the type is char or Character + */ + public static boolean hasSingleCharacterArg(Closure c) { + if (c.getMaximumNumberOfParameters() != 1) return false; + String typeName = c.getParameterTypes()[0].getName(); + return typeName.equals("char") || typeName.equals("java.lang.Character"); + } + + /** + * Does the Closure have a single String argument. + * @param c a Closure + * @return true if it has exactly one argument and the type is String + */ + public static boolean hasSingleStringArg(Closure c) { + if (c.getMaximumNumberOfParameters() != 1) return false; + String typeName = c.getParameterTypes()[0].getName(); + return typeName.equals("java.lang.String"); + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java new file mode 100644 index 0000000..252d6e3 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java @@ -0,0 +1,798 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast.tools; + +import org.codehaus.groovy.ast.ASTNode; +import org.codehaus.groovy.ast.AnnotatedNode; +import org.codehaus.groovy.ast.AnnotationNode; +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.FieldNode; +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.PackageNode; +import org.codehaus.groovy.ast.Parameter; +import org.codehaus.groovy.ast.PropertyNode; +import org.codehaus.groovy.ast.Variable; +import org.codehaus.groovy.ast.VariableScope; +import org.codehaus.groovy.ast.expr.ArgumentListExpression; +import org.codehaus.groovy.ast.expr.AttributeExpression; +import org.codehaus.groovy.ast.expr.BinaryExpression; +import org.codehaus.groovy.ast.expr.BooleanExpression; +import org.codehaus.groovy.ast.expr.CastExpression; +import org.codehaus.groovy.ast.expr.ClassExpression; +import org.codehaus.groovy.ast.expr.ClosureExpression; +import org.codehaus.groovy.ast.expr.ConstantExpression; +import org.codehaus.groovy.ast.expr.ConstructorCallExpression; +import org.codehaus.groovy.ast.expr.DeclarationExpression; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.FieldExpression; +import org.codehaus.groovy.ast.expr.MethodCallExpression; +import org.codehaus.groovy.ast.expr.NotExpression; +import org.codehaus.groovy.ast.expr.PropertyExpression; +import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; +import org.codehaus.groovy.ast.expr.TernaryExpression; +import org.codehaus.groovy.ast.expr.VariableExpression; +import org.codehaus.groovy.ast.stmt.BlockStatement; +import org.codehaus.groovy.ast.stmt.CatchStatement; +import org.codehaus.groovy.ast.stmt.EmptyStatement; +import org.codehaus.groovy.ast.stmt.ExpressionStatement; +import org.codehaus.groovy.ast.stmt.IfStatement; +import org.codehaus.groovy.ast.stmt.ReturnStatement; +import org.codehaus.groovy.ast.stmt.Statement; +import org.codehaus.groovy.ast.stmt.ThrowStatement; +import org.codehaus.groovy.classgen.Verifier; +import org.codehaus.groovy.control.io.ReaderSource; +import org.codehaus.groovy.runtime.GeneratedClosure; +import org.codehaus.groovy.runtime.MetaClassHelper; +import org.codehaus.groovy.syntax.Token; +import org.codehaus.groovy.syntax.Types; +import org.codehaus.groovy.transform.AbstractASTTransformation; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Handy methods when working with the Groovy AST + */ +public class GeneralUtils { + public static final Token ASSIGN = Token.newSymbol(Types.ASSIGN, -1, -1); + public static final Token EQ = Token.newSymbol(Types.COMPARE_EQUAL, -1, -1); + public static final Token NE = Token.newSymbol(Types.COMPARE_NOT_EQUAL, -1, -1); + public static final Token LT = Token.newSymbol(Types.COMPARE_LESS_THAN, -1, -1); + public static final Token AND = Token.newSymbol(Types.LOGICAL_AND, -1, -1); + public static final Token OR = Token.newSymbol(Types.LOGICAL_OR, -1, -1); + public static final Token CMP = Token.newSymbol(Types.COMPARE_TO, -1, -1); + private static final Token INSTANCEOF = Token.newSymbol(Types.KEYWORD_INSTANCEOF, -1, -1); + private static final Token PLUS = Token.newSymbol(Types.PLUS, -1, -1); + private static final Token INDEX = Token.newSymbol("[", -1, -1); + + public static BinaryExpression andX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, AND, rhv); + } + + public static ArgumentListExpression args(Expression... expressions) { + List<Expression> args = new ArrayList<Expression>(); + Collections.addAll(args, expressions); + return new ArgumentListExpression(args); + } + + public static ArgumentListExpression args(List<Expression> expressions) { + return new ArgumentListExpression(expressions); + } + + public static ArgumentListExpression args(Parameter[] parameters) { + return new ArgumentListExpression(parameters); + } + + public static ArgumentListExpression args(String... names) { + List<Expression> vars = new ArrayList<Expression>(); + for (String name : names) { + vars.add(varX(name)); + } + return new ArgumentListExpression(vars); + } + + public static Statement assignS(Expression target, Expression value) { + return new ExpressionStatement(assignX(target, value)); + } + + public static Expression assignX(Expression target, Expression value) { + return new BinaryExpression(target, ASSIGN, value); + } + + public static Expression attrX(Expression oe, Expression prop) { + return new AttributeExpression(oe, prop); + } + + public static BinaryExpression binX(Expression left, Token token, Expression right) { + return new BinaryExpression(left, token, right); + } + + public static BlockStatement block(VariableScope varScope, Statement... stmts) { + BlockStatement block = new BlockStatement(); + block.setVariableScope(varScope); + for (Statement stmt : stmts) block.addStatement(stmt); + return block; + } + + public static BlockStatement block(VariableScope varScope, List<Statement> stmts) { + BlockStatement block = new BlockStatement(); + block.setVariableScope(varScope); + for (Statement stmt : stmts) block.addStatement(stmt); + return block; + } + + public static BlockStatement block(Statement... stmts) { + BlockStatement block = new BlockStatement(); + for (Statement stmt : stmts) block.addStatement(stmt); + return block; + } + + public static MethodCallExpression callSuperX(String methodName, Expression args) { + return callX(varX("super"), methodName, args); + } + + public static MethodCallExpression callSuperX(String methodName) { + return callSuperX(methodName, MethodCallExpression.NO_ARGUMENTS); + } + + public static MethodCallExpression callThisX(String methodName, Expression args) { + return callX(varX("this"), methodName, args); + } + + public static MethodCallExpression callThisX(String methodName) { + return callThisX(methodName, MethodCallExpression.NO_ARGUMENTS); + } + + public static MethodCallExpression callX(Expression receiver, String methodName, Expression args) { + return new MethodCallExpression(receiver, methodName, args); + } + + public static MethodCallExpression callX(Expression receiver, Expression method, Expression args) { + return new MethodCallExpression(receiver, method, args); + } + + public static MethodCallExpression callX(Expression receiver, String methodName) { + return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS); + } + + public static StaticMethodCallExpression callX(ClassNode receiver, String methodName, Expression args) { + return new StaticMethodCallExpression(receiver, methodName, args); + } + + public static StaticMethodCallExpression callX(ClassNode receiver, String methodName) { + return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS); + } + + public static CastExpression castX(ClassNode type, Expression expression) { + return new CastExpression(type, expression); + } + + public static CastExpression castX(ClassNode type, Expression expression, boolean ignoreAutoboxing) { + return new CastExpression(type, expression, ignoreAutoboxing); + } + + public static ClassExpression classX(ClassNode clazz) { + return new ClassExpression(clazz); + } + + public static ClassExpression classX(Class clazz) { + return classX(ClassHelper.make(clazz).getPlainNodeReference()); + } + + public static ClosureExpression closureX(Parameter[] params, Statement code) { + return new ClosureExpression(params, code); + } + + public static ClosureExpression closureX(Statement code) { + return closureX(Parameter.EMPTY_ARRAY, code); + } + + public static Parameter[] cloneParams(Parameter[] source) { + Parameter[] result = new Parameter[source.length]; + for (int i = 0; i < source.length; i++) { + Parameter srcParam = source[i]; + Parameter dstParam = new Parameter(srcParam.getOriginType(), srcParam.getName()); + result[i] = dstParam; + } + return result; + } + + /** + * Build a binary expression that compares two values + * @param lhv expression for the value to compare from + * @param rhv expression for the value value to compare to + * @return the expression comparing two values + */ + public static BinaryExpression cmpX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, CMP, rhv); + } + + public static ConstantExpression constX(Object val) { + return new ConstantExpression(val); + } + + public static ConstantExpression constX(Object val, boolean keepPrimitive) { + return new ConstantExpression(val, keepPrimitive); + } + + /** + * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME} + * and {@link java.lang.annotation.RetentionPolicy#CLASS}. + * <p> + * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported at present. + */ + public static void copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, final List<AnnotationNode> copied, List<AnnotationNode> notCopied) { + List<AnnotationNode> annotationList = annotatedNode.getAnnotations(); + for (AnnotationNode annotation : annotationList) { + + List<AnnotationNode> annotations = annotation.getClassNode().getAnnotations(AbstractASTTransformation.RETENTION_CLASSNODE); + if (annotations.isEmpty()) continue; + + if (hasClosureMember(annotation)) { + notCopied.add(annotation); + continue; + } + + AnnotationNode retentionPolicyAnnotation = annotations.get(0); + Expression valueExpression = retentionPolicyAnnotation.getMember("value"); + if (!(valueExpression instanceof PropertyExpression)) continue; + + PropertyExpression propertyExpression = (PropertyExpression) valueExpression; + boolean processAnnotation = + propertyExpression.getProperty() instanceof ConstantExpression && + ( + "RUNTIME".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue()) || + "CLASS".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue()) + ); + + if (processAnnotation) { + AnnotationNode newAnnotation = new AnnotationNode(annotation.getClassNode()); + for (Map.Entry<String, Expression> member : annotation.getMembers().entrySet()) { + newAnnotation.addMember(member.getKey(), member.getValue()); + } + newAnnotation.setSourcePosition(annotatedNode); + + copied.add(newAnnotation); + } + } + } + + public static Statement createConstructorStatementDefault(FieldNode fNode) { + final String name = fNode.getName(); + final ClassNode fType = fNode.getType(); + final Expression fieldExpr = propX(varX("this"), name); + Expression initExpr = fNode.getInitialValueExpression(); + Statement assignInit; + if (initExpr == null || (initExpr instanceof ConstantExpression && ((ConstantExpression)initExpr).isNullExpression())) { + if (ClassHelper.isPrimitiveType(fType)) { + assignInit = EmptyStatement.INSTANCE; + } else { + assignInit = assignS(fieldExpr, ConstantExpression.EMPTY_EXPRESSION); + } + } else { + assignInit = assignS(fieldExpr, initExpr); + } + fNode.setInitialValueExpression(null); + Expression value = findArg(name); + return ifElseS(equalsNullX(value), assignInit, assignS(fieldExpr, castX(fType, value))); + } + + public static ConstructorCallExpression ctorX(ClassNode type, Expression args) { + return new ConstructorCallExpression(type, args); + } + + public static ConstructorCallExpression ctorX(ClassNode type) { + return new ConstructorCallExpression(type, ArgumentListExpression.EMPTY_ARGUMENTS); + } + + public static Statement ctorSuperS(Expression args) { + return stmt(ctorX(ClassNode.SUPER, args)); + } + + public static Statement ctorThisS(Expression args) { + return stmt(ctorX(ClassNode.THIS, args)); + } + + public static Statement ctorSuperS() { + return stmt(ctorX(ClassNode.SUPER)); + } + + public static Statement ctorThisS() { + return stmt(ctorX(ClassNode.THIS)); + } + + public static Statement declS(Expression target, Expression init) { + return new ExpressionStatement(new DeclarationExpression(target, ASSIGN, init)); + } + + public static BinaryExpression eqX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, EQ, rhv); + } + + public static BooleanExpression equalsNullX(Expression argExpr) { + return new BooleanExpression(eqX(argExpr, new ConstantExpression(null))); + } + + public static FieldExpression fieldX(FieldNode fieldNode) { + return new FieldExpression(fieldNode); + } + + public static FieldExpression fieldX(ClassNode owner, String fieldName) { + return new FieldExpression(owner.getField(fieldName)); + } + + public static Expression findArg(String argName) { + return new PropertyExpression(new VariableExpression("args"), argName); + } + + public static List<MethodNode> getAllMethods(ClassNode type) { + ClassNode node = type; + List<MethodNode> result = new ArrayList<MethodNode>(); + while (node != null) { + result.addAll(node.getMethods()); + node = node.getSuperClass(); + } + return result; + } + + public static List<PropertyNode> getAllProperties(ClassNode type) { + ClassNode node = type; + List<PropertyNode> result = new ArrayList<PropertyNode>(); + while (node != null) { + result.addAll(node.getProperties()); + node = node.getSuperClass(); + } + return result; + } + + public static String getGetterName(PropertyNode pNode) { + return "get" + Verifier.capitalize(pNode.getName()); + } + + public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) { + final List<FieldNode> result = new ArrayList<FieldNode>(); + for (FieldNode fNode : cNode.getFields()) { + if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) { + result.add(fNode); + } + } + return result; + } + + public static List<String> getInstanceNonPropertyFieldNames(ClassNode cNode) { + List<FieldNode> fList = getInstanceNonPropertyFields(cNode); + List<String> result = new ArrayList<String>(fList.size()); + for (FieldNode fNode : fList) { + result.add(fNode.getName()); + } + return result; + } + + public static List<PropertyNode> getInstanceProperties(ClassNode cNode) { + final List<PropertyNode> result = new ArrayList<PropertyNode>(); + for (PropertyNode pNode : cNode.getProperties()) { + if (!pNode.isStatic()) { + result.add(pNode); + } + } + return result; + } + + public static List<String> getInstancePropertyNames(ClassNode cNode) { + List<PropertyNode> pList = BeanUtils.getAllProperties(cNode, false, false, true); + List<String> result = new ArrayList<String>(pList.size()); + for (PropertyNode pNode : pList) { + result.add(pNode.getName()); + } + return result; + } + + public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) { + final List<FieldNode> result = new ArrayList<FieldNode>(); + for (PropertyNode pNode : cNode.getProperties()) { + if (!pNode.isStatic()) { + result.add(pNode.getField()); + } + } + return result; + } + + public static Set<ClassNode> getInterfacesAndSuperInterfaces(ClassNode type) { + Set<ClassNode> res = new LinkedHashSet<ClassNode>(); + if (type.isInterface()) { + res.add(type); + return res; + } + ClassNode next = type; + while (next != null) { + res.addAll(next.getAllInterfaces()); + next = next.getSuperClass(); + } + return res; + } + + public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) { + final List<FieldNode> result; + if (cNode == ClassHelper.OBJECT_TYPE) { + result = new ArrayList<FieldNode>(); + } else { + result = getSuperNonPropertyFields(cNode.getSuperClass()); + } + for (FieldNode fNode : cNode.getFields()) { + if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) { + result.add(fNode); + } + } + return result; + } + + public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) { + final List<FieldNode> result; + if (cNode == ClassHelper.OBJECT_TYPE) { + result = new ArrayList<FieldNode>(); + } else { + result = getSuperPropertyFields(cNode.getSuperClass()); + } + for (PropertyNode pNode : cNode.getProperties()) { + if (!pNode.isStatic()) { + result.add(pNode.getField()); + } + } + return result; + } + + public static BinaryExpression hasClassX(Expression instance, ClassNode cNode) { + return eqX(classX(cNode), callX(instance, "getClass")); + } + + private static boolean hasClosureMember(AnnotationNode annotation) { + + Map<String, Expression> members = annotation.getMembers(); + for (Map.Entry<String, Expression> member : members.entrySet()) { + if (member.getValue() instanceof ClosureExpression) return true; + + if (member.getValue() instanceof ClassExpression) { + ClassExpression classExpression = (ClassExpression) member.getValue(); + Class<?> typeClass = classExpression.getType().isResolved() ? classExpression.getType().redirect().getTypeClass() : null; + if (typeClass != null && GeneratedClosure.class.isAssignableFrom(typeClass)) return true; + } + } + + return false; + } + + public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) { + List<MethodNode> ms = cNode.getDeclaredMethods(name); + for (MethodNode m : ms) { + Parameter[] paras = m.getParameters(); + if (paras != null && paras.length == argsCount) { + return true; + } + } + return false; + } + + public static BinaryExpression hasEqualFieldX(FieldNode fNode, Expression other) { + return eqX(varX(fNode), propX(other, fNode.getName())); + } + + public static BinaryExpression hasEqualPropertyX(ClassNode annotatedNode, PropertyNode pNode, VariableExpression other) { + return eqX(getterThisX(annotatedNode, pNode), getterX(other.getOriginType(), other, pNode)); + } + + @Deprecated + public static BinaryExpression hasEqualPropertyX(PropertyNode pNode, Expression other) { + String getterName = getGetterName(pNode); + return eqX(callThisX(getterName), callX(other, getterName)); + } + + public static BooleanExpression hasSameFieldX(FieldNode fNode, Expression other) { + return sameX(varX(fNode), propX(other, fNode.getName())); + } + + public static BooleanExpression hasSamePropertyX(PropertyNode pNode, Expression other) { + ClassNode cNode = pNode.getDeclaringClass(); + return sameX(getterThisX(cNode, pNode), getterX(cNode, other, pNode)); + } + + public static Statement ifElseS(Expression cond, Statement thenStmt, Statement elseStmt) { + return new IfStatement( + cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond), + thenStmt, + elseStmt + ); + } + + public static Statement ifS(Expression cond, Expression trueExpr) { + return ifS(cond, new ExpressionStatement(trueExpr)); + } + + public static Statement ifS(Expression cond, Statement trueStmt) { + return new IfStatement( + cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond), + trueStmt, + EmptyStatement.INSTANCE + ); + } + + public static Expression indexX(Expression target, Expression value) { + return new BinaryExpression(target, INDEX, value); + } + + public static BooleanExpression isInstanceOfX(Expression objectExpression, ClassNode cNode) { + return new BooleanExpression(new BinaryExpression(objectExpression, INSTANCEOF, classX(cNode))); + } + + public static BooleanExpression isOneX(Expression expr) { + return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(1))); + } + + public static boolean isOrImplements(ClassNode type, ClassNode interfaceType) { + return type.equals(interfaceType) || type.implementsInterface(interfaceType); + } + + public static BooleanExpression isTrueX(Expression argExpr) { + return new BooleanExpression(new BinaryExpression(argExpr, EQ, new ConstantExpression(Boolean.TRUE))); + } + + public static BooleanExpression isZeroX(Expression expr) { + return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(0))); + } + + public static BinaryExpression ltX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, LT, rhv); + } + + /** + * @deprecated use MethodNodeUtils#methodDescriptorWithoutReturnType(MethodNode) instead + */ + @Deprecated + public static String makeDescriptorWithoutReturnType(MethodNode mn) { + StringBuilder sb = new StringBuilder(); + sb.append(mn.getName()).append(':'); + for (Parameter p : mn.getParameters()) { + sb.append(p.getType()).append(','); + } + return sb.toString(); + } + + public static BinaryExpression neX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, NE, rhv); + } + + public static BooleanExpression notNullX(Expression argExpr) { + return new BooleanExpression(new BinaryExpression(argExpr, NE, new ConstantExpression(null))); + } + + public static NotExpression notX(Expression expr) { + return new NotExpression(expr instanceof BooleanExpression ? expr : new BooleanExpression(expr)); + } + + public static BinaryExpression orX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, OR, rhv); + } + + public static Parameter param(ClassNode type, String name) { + return param(type, name, null); + } + + public static Parameter param(ClassNode type, String name, Expression initialExpression) { + Parameter param = new Parameter(type, name); + if (initialExpression != null) { + param.setInitialExpression(initialExpression); + } + return param; + } + + public static Parameter[] params(Parameter... params) { + return params != null ? params : Parameter.EMPTY_ARRAY; + } + + public static BinaryExpression plusX(Expression lhv, Expression rhv) { + return new BinaryExpression(lhv, PLUS, rhv); + } + + public static Expression propX(Expression owner, String property) { + return new PropertyExpression(owner, property); + } + + public static Expression propX(Expression owner, Expression property) { + return new PropertyExpression(owner, property); + } + + public static Statement returnS(Expression expr) { + return new ReturnStatement(new ExpressionStatement(expr)); + } + + public static Statement safeExpression(Expression fieldExpr, Expression expression) { + return new IfStatement( + equalsNullX(fieldExpr), + new ExpressionStatement(fieldExpr), + new ExpressionStatement(expression)); + } + + public static BooleanExpression sameX(Expression self, Expression other) { + return new BooleanExpression(callX(self, "is", args(other))); + } + + public static Statement stmt(Expression expr) { + return new ExpressionStatement(expr); + } + + public static TernaryExpression ternaryX(Expression cond, Expression trueExpr, Expression elseExpr) { + return new TernaryExpression( + cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond), + trueExpr, + elseExpr); + } + + public static VariableExpression varX(String name) { + return new VariableExpression(name); + } + + public static VariableExpression varX(Variable variable) { + return new VariableExpression(variable); + } + + public static VariableExpression varX(String name, ClassNode type) { + return new VariableExpression(name, type); + } + + public static ThrowStatement throwS(Expression expr) { + return new ThrowStatement(expr); + } + + public static CatchStatement catchS(Parameter variable, Statement code) { + return new CatchStatement(variable, code); + } + + /** + * This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property + * being accessed is defined inside the classnode provided as a parameter, then a getter call is generated + * instead of a field access. + * @param annotatedNode the class node where the property node is accessed from + * @param pNode the property being accessed + * @return a method call expression or a property expression + */ + public static Expression getterThisX(ClassNode annotatedNode, PropertyNode pNode) { + ClassNode owner = pNode.getDeclaringClass(); + if (annotatedNode.equals(owner)) { + return callThisX(getterName(annotatedNode, pNode)); + } + return propX(new VariableExpression("this"), pNode.getName()); + } + + private static String getterName(ClassNode annotatedNode, PropertyNode pNode) { + String getterName = "get" + MetaClassHelper.capitalize(pNode.getName()); + boolean existingExplicitGetter = annotatedNode.getMethod(getterName, Parameter.EMPTY_ARRAY) != null; + if (ClassHelper.boolean_TYPE.equals(pNode.getOriginType()) && !existingExplicitGetter) { + getterName = "is" + MetaClassHelper.capitalize(pNode.getName()); + } + return getterName; + } + + /** + * This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property + * being accessed is defined inside the classnode provided as a parameter, then a getter call is generated + * instead of a field access. + * @param annotatedNode the class node where the property node is accessed from + * @param receiver the object having the property + * @param pNode the property being accessed + * @return a method call expression or a property expression + */ + public static Expression getterX(ClassNode annotatedNode, Expression receiver, PropertyNode pNode) { + ClassNode owner = pNode.getDeclaringClass(); + if (annotatedNode.equals(owner)) { + return callX(receiver, getterName(annotatedNode, pNode)); + } + return propX(receiver, pNode.getName()); + } + + /** + * Converts an expression into the String source. Only some specific expressions like closure expression + * support this. + * + * @param readerSource a source + * @param expression an expression. Can't be null + * @return the source the closure was created from + * @throws java.lang.IllegalArgumentException when expression is null + * @throws java.lang.Exception when closure can't be read from source + */ + public static String convertASTToSource(ReaderSource readerSource, ASTNode expression) throws Exception { + if (expression == null) throw new IllegalArgumentException("Null: expression"); + + StringBuilder result = new StringBuilder(); + for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) { + String line = readerSource.getLine(x, null); + if (line == null) { + throw new Exception( + "Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass() + ); + } + if (x == expression.getLastLineNumber()) { + line = line.substring(0, expression.getLastColumnNumber() - 1); + } + if (x == expression.getLineNumber()) { + line = line.substring(expression.getColumnNumber() - 1); + } + //restoring line breaks is important b/c of lack of semicolons + result.append(line).append('\n'); + } + + + String source = result.toString().trim(); + + return source; + } + + public static boolean copyStatementsWithSuperAdjustment(ClosureExpression pre, BlockStatement body) { + Statement preCode = pre.getCode(); + boolean changed = false; + if (preCode instanceof BlockStatement) { + BlockStatement block = (BlockStatement) preCode; + List<Statement> statements = block.getStatements(); + for (int i = 0; i < statements.size(); i++) { + Statement statement = statements.get(i); + // adjust the first statement if it's a super call + if (i == 0 && statement instanceof ExpressionStatement) { + ExpressionStatement es = (ExpressionStatement) statement; + Expression preExp = es.getExpression(); + if (preExp instanceof MethodCallExpression) { + MethodCallExpression mce = (MethodCallExpression) preExp; + String name = mce.getMethodAsString(); + if ("super".equals(name)) { + es.setExpression(new ConstructorCallExpression(ClassNode.SUPER, mce.getArguments())); + changed = true; + } + } + } + body.addStatement(statement); + } + } + return changed; + } + + public static String getSetterName(String name) { + return "set" + Verifier.capitalize(name); + } + + public static boolean isDefaultVisibility(int modifiers) { + return (modifiers & (Modifier.PRIVATE | Modifier.PUBLIC | Modifier.PROTECTED)) == 0; + } + + public static boolean inSamePackage(ClassNode first, ClassNode second) { + PackageNode firstPackage = first.getPackage(); + PackageNode secondPackage = second.getPackage(); + return ((firstPackage == null && secondPackage == null) || + firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName())); + } + + public static boolean inSamePackage(Class first, Class second) { + Package firstPackage = first.getPackage(); + Package secondPackage = second.getPackage(); + return ((firstPackage == null && secondPackage == null) || + firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName())); + } +}
