public FlyweightCapableTreeStructure<LighterASTNode> parseContentsLight(final ASTNode chameleon) { final PsiElement psi = chameleon.getPsi(); assert psi != null : "Bad chameleon: " + chameleon; final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); final PsiBuilder builder = factory.createBuilder(project, chameleon); final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(getLanguage()); assert parserDefinition != null : this; final PsiParser parser = parserDefinition.createParser(project); if (parser instanceof LightPsiParser) { ((LightPsiParser)parser).parseLight(this, builder); } else { parser.parse(this, builder); } return builder.getLightTree(); }
@Override public ThreeState fun(ASTNode oldNode, LighterASTNode newNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { if (oldNode instanceof XmlTag && newNode.getTokenType() == XmlElementType.XML_TAG) { String oldName = ((XmlTag)oldNode).getName(); Ref<LighterASTNode[]> childrenRef = Ref.create(null); int count = structure.getChildren(newNode, childrenRef); if (count < 3) return ThreeState.UNSURE; LighterASTNode[] children = childrenRef.get(); if (children[0].getTokenType() != XmlTokenType.XML_START_TAG_START) return ThreeState.UNSURE; if (children[1].getTokenType() != XmlTokenType.XML_NAME) return ThreeState.UNSURE; if (children[2].getTokenType() != XmlTokenType.XML_TAG_END) return ThreeState.UNSURE; LighterASTTokenNode name = (LighterASTTokenNode)children[1]; CharSequence newName = name.getText(); if (!Comparing.equal(oldName, newName)) return ThreeState.NO; } return ThreeState.UNSURE; }
public void build(XmlBuilder builder) { PsiBuilder b = createBuilderAndParse(); FlyweightCapableTreeStructure<LighterASTNode> structure = b.getLightTree(); LighterASTNode root = structure.getRoot(); root = structure.prepareForGetChildren(root); final Ref<LighterASTNode[]> childrenRef = Ref.create(null); final int count = structure.getChildren(root, childrenRef); LighterASTNode[] children = childrenRef.get(); for (int i = 0; i < count; i++) { LighterASTNode child = children[i]; final IElementType tt = child.getTokenType(); if (tt == XmlElementType.XML_TAG || tt == XmlElementType.HTML_TAG) { processTagNode(b, structure, child, builder); } else if (tt == XmlElementType.XML_PROLOG) { processPrologNode(b, builder, structure, child); } } structure.disposeChildren(children, count); }
private void processPrologNode(PsiBuilder psiBuilder, XmlBuilder builder, FlyweightCapableTreeStructure<LighterASTNode> structure, LighterASTNode prolog) { final Ref<LighterASTNode[]> prologChildren = new Ref<LighterASTNode[]>(null); final int prologChildrenCount = structure.getChildren(structure.prepareForGetChildren(prolog), prologChildren); for (int i = 0; i < prologChildrenCount; i++) { LighterASTNode node = prologChildren.get()[i]; IElementType type = node.getTokenType(); if (type == XmlElementType.XML_DOCTYPE) { processDoctypeNode(builder, structure, node); break; } if (type == TokenType.ERROR_ELEMENT) { processErrorNode(psiBuilder, node, builder); } } }
private CharSequence findTextByTokenType(LighterASTNode attrNode, FlyweightCapableTreeStructure<LighterASTNode> structure, IElementType tt) { attrNode = structure.prepareForGetChildren(attrNode); final Ref<LighterASTNode[]> childrenRef = Ref.create(null); final int count = structure.getChildren(attrNode, childrenRef); LighterASTNode[] children = childrenRef.get(); CharSequence name = ""; for (int i = 0; i < count; i++) { LighterASTNode child = children[i]; if (child.getTokenType() == tt) { name = getTokenText(child); break; } } structure.disposeChildren(children, count); return name; }
@Override public ThreeState fun(ASTNode oldNode, LighterASTNode newNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { if (oldNode.getElementType() == PropertiesElementTypes.PROPERTY) { ASTNode oldName = oldNode.findChildByType(PropertiesTokenTypes.KEY_CHARACTERS); if (oldName != null) { CharSequence oldNameStr = oldName.getChars(); CharSequence newNameStr = findKeyCharacters(newNode, structure); if (oldNameStr != null && !Comparing.equal(oldNameStr, newNameStr)) { return ThreeState.NO; } } } return ThreeState.UNSURE; }
private static CharSequence findKeyCharacters(LighterASTNode newNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { Ref<LighterASTNode[]> childrenRef = Ref.create(null); int childrenCount = structure.getChildren(newNode, childrenRef); LighterASTNode[] children = childrenRef.get(); try { for (int i = 0; i < children.length; ++i) { if (children[i].getTokenType() == PropertiesTokenTypes.KEY_CHARACTERS) return ((LighterASTTokenNode) children[i]).getText(); } return null; } finally { structure.disposeChildren(children, childrenCount); } }
@Override public ThreeState fun(ASTNode oldNode, LighterASTNode newNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { if (oldNode instanceof XmlTag && newNode.getTokenType() == XmlElementType.XML_TAG) { String oldName = ((XmlTag)oldNode).getName(); Ref<LighterASTNode[]> childrenRef = Ref.create(null); int count = structure.getChildren(newNode, childrenRef); if (count < 3) return ThreeState.UNSURE; LighterASTNode[] children = childrenRef.get(); if (children[0].getTokenType() != XmlTokenType.XML_START_TAG_START) return ThreeState.UNSURE; if (children[1].getTokenType() != XmlTokenType.XML_NAME) return ThreeState.UNSURE; if (children[2].getTokenType() != XmlTokenType.XML_TAG_END) return ThreeState.UNSURE; LighterASTTokenNode name = (LighterASTTokenNode)children[1]; CharSequence newName = name.getText(); if (!oldName.equals(newName)) return ThreeState.NO; } return ThreeState.UNSURE; }
@NotNull @Override public JBIterable<? extends T> children(@NotNull final T node) { return new JBIterable<T>() { @Override public Iterator<T> iterator() { FlyweightCapableTreeStructure<T> structure = getStructure(); Ref<T[]> ref = Ref.create(); int count = structure.getChildren(structure.prepareForGetChildren(node), ref); if (count == 0) return ContainerUtil.emptyIterator(); T[] array = ref.get(); LinkedList<T> list = ContainerUtil.newLinkedList(); for (int i = 0; i < count; i++) { T child = array[i]; IElementType childType = typeOf(child); // skip TokenType.* types, errors cannot be properly handled (no parents) if (childType == TokenType.ERROR_ELEMENT) { // todo remember error continue; } else if (childType == TokenType.WHITE_SPACE || childType == TokenType.BAD_CHARACTER) { continue; } array[i] = null; // do not dispose meaningful TokenNodes list.addLast(child); } structure.disposeChildren(array, count); return list.iterator(); } }; }
@Override public int getChildren(@NotNull final LighterASTNode item, @NotNull final Ref<LighterASTNode[]> into) { if (item instanceof LazyParseableToken) { final FlyweightCapableTreeStructure<LighterASTNode> tree = ((LazyParseableToken)item).parseContents(); final LighterASTNode root = tree.getRoot(); return tree.getChildren(tree.prepareForGetChildren(root), into); // todo: set offset shift for kids? } if (item instanceof Token || item instanceof ErrorItem) return 0; StartMarker marker = (StartMarker)item; count = 0; ProductionMarker child = marker.myFirstChild; int lexIndex = marker.myLexemeIndex; while (child != null) { lexIndex = insertLeaves(lexIndex, child.myLexemeIndex, marker.myBuilder); if (child instanceof StartMarker && ((StartMarker)child).myDoneMarker.myCollapse) { int lastIndex = ((StartMarker)child).myDoneMarker.myLexemeIndex; insertLeaf(child.getTokenType(), marker.myBuilder, child.myLexemeIndex, lastIndex, true); } else { ensureCapacity(); nodes[count++] = child; } if (child instanceof StartMarker) { lexIndex = ((StartMarker)child).myDoneMarker.myLexemeIndex; } child = child.myNext; } insertLeaves(lexIndex, marker.myDoneMarker.myLexemeIndex, marker.myBuilder); into.set(nodes == null ? LighterASTNode.EMPTY_ARRAY : nodes); nodes = null; return count; }
public static String lightTreeToString(@NotNull final FlyweightCapableTreeStructure<LighterASTNode> tree, final boolean skipWhitespaces) { final LengthBuilder ruler = new LengthBuilder(); lightTreeToBuffer(tree, tree.getRoot(), ruler, 0, skipWhitespaces); final StringBuilder buffer = new StringBuilder(ruler.getLength()); lightTreeToBuffer(tree, tree.getRoot(), buffer, 0, skipWhitespaces); return buffer.toString(); }
public static <T> void diffTrees(@NotNull final ASTNode oldRoot, @NotNull final DiffTreeChangeBuilder<ASTNode, T> builder, @NotNull final ShallowNodeComparator<ASTNode, T> comparator, @NotNull final FlyweightCapableTreeStructure<T> newTreeStructure, @NotNull ProgressIndicator indicator, @NotNull CharSequence lastCommittedText) { TreeUtil.ensureParsedRecursivelyCheckingProgress(oldRoot, indicator); DiffTree.diff(createInterruptibleASTStructure(oldRoot, indicator), newTreeStructure, comparator, builder, lastCommittedText); }
@Override public FlyweightCapableTreeStructure<LighterASTNode> parseContents(LighterLazyParseableNode chameleon) { final PsiFile file = chameleon.getContainingFile(); assert file != null : chameleon; final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(file.getProject(), chameleon); HTMLParser.parseWithoutBuildingTree(HTML_FILE, builder); return builder.getLightTree(); }
private void processDoctypeNode(final XmlBuilder builder, final FlyweightCapableTreeStructure<LighterASTNode> structure, final LighterASTNode doctype) { final Ref<LighterASTNode[]> tokens = new Ref<LighterASTNode[]>(null); final int tokenCount = structure.getChildren(structure.prepareForGetChildren(doctype), tokens); if (tokenCount > 0) { CharSequence publicId = null; boolean afterPublic = false; CharSequence systemId = null; boolean afterSystem = false; for (int i = 0; i < tokenCount; i++) { LighterASTNode token = tokens.get()[i]; if (token.getTokenType() == XmlTokenType.XML_DOCTYPE_PUBLIC) { afterPublic = true; } else if (token.getTokenType() == XmlTokenType.XML_DOCTYPE_SYSTEM) { afterSystem = true; } else if (token.getTokenType() != TokenType.WHITE_SPACE && token.getTokenType() != XmlElementType.XML_COMMENT) { if (token.getTokenType() == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN) { if (afterPublic) publicId = getTokenText(token); else if (afterSystem) systemId = getTokenText(token); } afterPublic = afterSystem = false; } } builder.doctype(publicId, systemId, doctype.getStartOffset(), doctype.getEndOffset()); } }
private void processTextNode(FlyweightCapableTreeStructure<LighterASTNode> structure, LighterASTNode node, XmlBuilder builder) { node = structure.prepareForGetChildren(node); final Ref<LighterASTNode[]> childrenRef = Ref.create(null); final int count = structure.getChildren(node, childrenRef); LighterASTNode[] children = childrenRef.get(); for (int i = 0; i < count; i++) { LighterASTNode child = children[i]; IElementType tt = child.getTokenType(); final int start = child.getStartOffset(); final int end = child.getEndOffset(); final CharSequence physical = getTokenText(child); if (XmlTokenType.COMMENTS.contains(tt)) continue; if (tt == XmlTokenType.XML_CDATA_START || tt == XmlTokenType.XML_CDATA_END) { builder.textElement("", physical, start, end); } else if (tt == XmlElementType.XML_CDATA) { processTextNode(structure, child, builder); } else if (tt == XmlTokenType.XML_CHAR_ENTITY_REF) { builder.textElement(new String(new char[] {XmlUtil.getCharFromEntityRef(physical.toString())}), physical, start, end); } else { builder.textElement(physical, physical, start, end); } } structure.disposeChildren(children, count); }
private void checkForXmlns(LighterASTNode attrNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { final CharSequence name = getAttributeName(attrNode, structure); if (Comparing.equal(name, XMLNS)) { myPrefixesStack.push(""); myNamespacesStack.push(getAttributeValue(attrNode, structure).toString()); } else if (StringUtil.startsWith(name, XMLNS_COLON)) { myPrefixesStack.push(name.subSequence(XMLNS_COLON.length(), name.length()).toString()); myNamespacesStack.push(getAttributeValue(attrNode, structure).toString()); } }
private CharSequence getAttributeValue(LighterASTNode attrNode, FlyweightCapableTreeStructure<LighterASTNode> structure) { final CharSequence fullValue = findTextByTokenType(attrNode, structure, XmlElementType.XML_ATTRIBUTE_VALUE); int start = 0; if (fullValue.length() > 0 && fullValue.charAt(0) == '\"') start++; int end = fullValue.length(); if (fullValue.length() > start && fullValue.charAt(fullValue.length() - 1) == '\"') end--; return fullValue.subSequence(start, end); }
public FlyweightCapableTreeStructure<LighterASTNode> parseContentsLight(final ASTNode chameleon) { final PsiElement psi = chameleon.getPsi(); assert psi != null : "Bad chameleon: " + chameleon; final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); final PsiBuilder builder = factory.createBuilder(project, chameleon); final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(getLanguage()); assert parserDefinition != null : this; final PsiParser parser = parserDefinition.createParser(project); parser.parse(this, builder); return builder.getLightTree(); }
@Override public int getChildren(@NotNull final LighterASTNode item, @NotNull final Ref<LighterASTNode[]> into) { if (item instanceof LazyParseableToken) { final FlyweightCapableTreeStructure<LighterASTNode> tree = ((LazyParseableToken)item).parseContents(); final LighterASTNode root = tree.getRoot(); return tree.getChildren(tree.prepareForGetChildren(root), into); // todo: set offset shift for kids? } if (item instanceof Token || item instanceof ErrorItem) return 0; StartMarker marker = (StartMarker)item; count = 0; ProductionMarker child = marker.myFirstChild; int lexIndex = marker.myLexemeIndex; while (child != null) { lexIndex = insertLeaves(lexIndex, child.myLexemeIndex, marker.myBuilder); if (child instanceof StartMarker && ((StartMarker)child).myDoneMarker.myCollapse) { int lastIndex = ((StartMarker)child).myDoneMarker.myLexemeIndex; insertLeaf(child.getTokenType(), marker.myBuilder, child.myLexemeIndex, lastIndex); } else { ensureCapacity(); nodes[count++] = child; } if (child instanceof StartMarker) { lexIndex = ((StartMarker)child).myDoneMarker.myLexemeIndex; } child = child.myNext; } insertLeaves(lexIndex, marker.myDoneMarker.myLexemeIndex, marker.myBuilder); into.set(nodes); nodes = null; return count; }
public static <T> void diffTrees(@NotNull final ASTNode oldRoot, @NotNull final DiffTreeChangeBuilder<ASTNode, T> builder, @NotNull final ShallowNodeComparator<ASTNode, T> comparator, @NotNull final FlyweightCapableTreeStructure<T> newTreeStructure, final ProgressIndicator indicator) { TreeUtil.ensureParsedRecursivelyCheckingProgress(oldRoot, indicator); DiffTree.diff(createInterruptibleASTStructure(oldRoot, indicator), newTreeStructure, comparator, builder); }
private void processDoctypeNode(final XmlBuilder builder, final FlyweightCapableTreeStructure<LighterASTNode> structure, final LighterASTNode doctype) { final Ref<LighterASTNode[]> tokens = new Ref<LighterASTNode[]>(null); final int tokenCount = structure.getChildren(structure.prepareForGetChildren(doctype), tokens); if (tokenCount > 0) { CharSequence publicId = null; boolean afterPublic = false; CharSequence systemId = null; boolean afterSystem = false; for (int i = 0; i < tokenCount; i++) { LighterASTNode token = tokens.get()[i]; if (token.getTokenType() == XmlElementType.XML_DOCTYPE_PUBLIC) { afterPublic = true; } else if (token.getTokenType() == XmlElementType.XML_DOCTYPE_SYSTEM) { afterSystem = true; } else if (token.getTokenType() != TokenType.WHITE_SPACE && token.getTokenType() != XmlElementType.XML_COMMENT) { if (token.getTokenType() == XmlElementType.XML_ATTRIBUTE_VALUE_TOKEN) { if (afterPublic) publicId = getTokenText(token); else if (afterSystem) systemId = getTokenText(token); } afterPublic = afterSystem = false; } } builder.doctype(publicId, systemId, doctype.getStartOffset(), doctype.getEndOffset()); } }
@Override public FlyweightCapableTreeStructure<LighterASTNode> parseContentsLight(final ASTNode chameleon) { final PsiElement psi = chameleon.getPsi(); assert psi != null : "Bad chameleon: " + chameleon; final Project project = psi.getProject(); final LanguageVersion languageVersion = psi.getLanguageVersion(); return doParse(chameleon, project, languageVersion).getLightTree(); }
@Nonnull @Override public JBIterable<? extends T> children(@Nonnull final T node) { return new JBIterable<T>() { @Override public Iterator<T> iterator() { FlyweightCapableTreeStructure<T> structure = getStructure(); Ref<T[]> ref = Ref.create(); int count = structure.getChildren(node, ref); if (count == 0) return ContainerUtil.emptyIterator(); T[] array = ref.get(); LinkedList<T> list = ContainerUtil.newLinkedList(); for (int i = 0; i < count; i++) { T child = array[i]; IElementType childType = typeOf(child); // tokens and errors getParent() == null if (childType == TokenType.WHITE_SPACE || childType == TokenType.BAD_CHARACTER) { continue; } array[i] = null; // do not dispose meaningful TokenNodes list.addLast(child); } structure.disposeChildren(array, count); return list.iterator(); } }; }
public FlyweightCapableTreeStructure<LighterASTNode> parseContentsLight(final ASTNode chameleon) { final PsiElement psi = chameleon.getPsi(); assert psi != null : "Bad chameleon: " + chameleon; final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); final Language language = getLanguage(); final LanguageVersion languageVersion = psi.getLanguageVersion(); final PsiBuilder builder = factory.createBuilder(project, chameleon, languageVersion); final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language); assert parserDefinition != null : this; final PsiParser parser = parserDefinition.createParser(languageVersion); parser.parse(this, builder, languageVersion); return builder.getLightTree(); }
public static String lightTreeToString(@Nonnull final FlyweightCapableTreeStructure<LighterASTNode> tree, final boolean skipWhitespaces) { final LengthBuilder ruler = new LengthBuilder(); lightTreeToBuffer(tree, tree.getRoot(), ruler, 0, skipWhitespaces); final StringBuilder buffer = new StringBuilder(ruler.getLength()); lightTreeToBuffer(tree, tree.getRoot(), buffer, 0, skipWhitespaces); return buffer.toString(); }
public static <T> void diffTrees(@Nonnull final ASTNode oldRoot, @Nonnull final DiffTreeChangeBuilder<ASTNode, T> builder, @Nonnull final ShallowNodeComparator<ASTNode, T> comparator, @Nonnull final FlyweightCapableTreeStructure<T> newTreeStructure, @Nonnull ProgressIndicator indicator, @Nonnull CharSequence lastCommittedText) { TreeUtil.ensureParsedRecursivelyCheckingProgress(oldRoot, indicator); DiffTree.diff(createInterruptibleASTStructure(oldRoot, indicator), newTreeStructure, comparator, builder, lastCommittedText); }