| /* |
| * 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.netbeans.modules.web.el; |
| |
| import com.sun.el.parser.Node; |
| import com.sun.el.parser.NodeVisitor; |
| import javax.el.ELException; |
| import org.netbeans.modules.csl.api.OffsetRange; |
| import org.netbeans.modules.parsing.api.Snapshot; |
| |
| /** |
| * Represents the parse result of a single EL expression. |
| * |
| * @author Erno Mononen |
| */ |
| public final class ELElement { |
| |
| private final Node node; |
| private final OffsetRange embeddedOffset; |
| private final ELException error; |
| private final ELPreprocessor expression; |
| private final Snapshot snapshot; |
| private final OffsetRange originalOffset; |
| |
| private ELElement(Node node, ELException error, ELPreprocessor expression, OffsetRange embeddedOffset, Snapshot snapshot) { |
| assert node == null || error == null; |
| this.node = node; |
| this.embeddedOffset = embeddedOffset; |
| this.snapshot = snapshot; |
| this.error = error; |
| this.expression = expression; |
| |
| int origStart = snapshot.getOriginalOffset(embeddedOffset.getStart()); |
| int origEnd = snapshot.getOriginalOffset(embeddedOffset.getEnd()); |
| this.originalOffset = new OffsetRange(origStart, origEnd); |
| } |
| |
| static ELElement valid(Node node, ELPreprocessor expression, OffsetRange embeddedOffset, Snapshot snapshot) { |
| return new ELElement(node, null, expression, embeddedOffset, snapshot); |
| } |
| |
| static ELElement error(ELException error, ELPreprocessor expression, OffsetRange embeddedOffset, Snapshot snapshot) { |
| return new ELElement(null, error, expression, embeddedOffset, snapshot); |
| } |
| |
| /** |
| * Makes a copy of this, but with the given {@code node} and {@code expression}. |
| * Can't be invoked on valid elements, and the given {@code node} must represent |
| * a valid expression. |
| * |
| * @param node |
| * @param expression |
| * @return a copy of this but with the given {@code node} and {@code expression}. |
| */ |
| public ELElement makeValidCopy(Node node, ELPreprocessor expression) { |
| assert !isValid(); |
| return valid(node, expression, embeddedOffset, snapshot); |
| } |
| |
| /** |
| * Gets the root node of the expression. |
| * |
| * @return |
| */ |
| public Node getNode() { |
| return node; |
| } |
| |
| /** |
| * Gets the offset in the embedded source. |
| * @see #getOriginalOffset() |
| * @return |
| */ |
| public OffsetRange getEmbeddedOffset() { |
| return embeddedOffset; |
| } |
| |
| /** |
| * Gets the offset in the original document. |
| * @return |
| */ |
| public OffsetRange getOriginalOffset() { |
| return originalOffset; |
| } |
| |
| /** |
| * Gets the offset of the given {@code node} in the original document. |
| * @param node a node contained by this element. |
| * @return |
| */ |
| public OffsetRange getOriginalOffset(Node node) { |
| int start = originalOffset.getStart() + expression.getOriginalOffset(node.startOffset()); |
| int end = originalOffset.getStart() + expression.getOriginalOffset(node.endOffset()); |
| return new OffsetRange(start, end); |
| } |
| |
| public boolean isValid() { |
| return error == null; |
| } |
| |
| public ELException getError() { |
| return error; |
| } |
| |
| public ELPreprocessor getExpression() { |
| return expression; |
| } |
| |
| /** |
| * Gets the node at the given offset. |
| * @param offset an offset in the original document. |
| * @return the node at the given {@code offset} or {@code null}. |
| */ |
| public Node findNodeAt(final int offset) { |
| assert getOriginalOffset().containsInclusive(offset); |
| if (getNode() == null) { |
| return null; |
| } |
| final Node[] result = new Node[1]; |
| getNode().accept(new NodeVisitor() { |
| @Override |
| public void visit(Node node) throws ELException { |
| int nodeFrom = expression.getOriginalOffset(node.startOffset()); |
| int nodeTo = expression.getOriginalOffset(node.endOffset()); |
| if (originalOffset.getStart() + nodeFrom <= offset |
| && originalOffset.getStart() + nodeTo > offset) { |
| result[0] = node; |
| } |
| |
| } |
| }); |
| return result[0]; |
| } |
| |
| public Snapshot getSnapshot() { |
| return snapshot; |
| } |
| |
| @Override |
| public String toString() { |
| return "ELElement{expression=" + expression + " node=" + node + " offset=" + embeddedOffset + " error=" + error + '}'; |
| } |
| |
| } |