blob: c93bd114eb1a32da22e795f536b7e428a070429e [file] [log] [blame]
/*
* 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 + '}';
}
}