001/* 002 * Java Genetic Algorithm Library (jenetics-9.1.0). 003 * Copyright (c) 2007-2026 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.ext.rewriting; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.stream.Stream; 025 026import io.jenetics.ext.util.Tree; 027 028/** 029 * Implementation of a pattern-based tree matcher. It allows you to iterate over 030 * all matches of a tree for a given pattern. 031 * {@snippet lang="java": 032 * final TreePattern<String> pattern = TreePattern.compile("add($x,$y)"); 033 * final Tree<String, ?> tree = TreeNode.parse("add(1,add(2,3))"); 034 * final TreeMatcher<String> matcher = pattern.matcher(tree); 035 * matcher.results().forEach(r -> System.out.println(r.tree().toParenthesesString())); 036 * // Prints: 037 * // add(1,add(2,3)) 038 * // add(2,3) 039 * } 040 * 041 * @see TreePattern#matcher(Tree) 042 * 043 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 044 * @version 5.0 045 * @since 5.0 046 */ 047public final class TreeMatcher<V> { 048 049 private final TreePattern<V> _pattern; 050 private final Tree<V, ?> _tree; 051 052 private TreeMatcher(final TreePattern<V> pattern, final Tree<V, ?> tree) { 053 _pattern = requireNonNull(pattern); 054 _tree = requireNonNull(tree); 055 } 056 057 /** 058 * Return the underlying pattern of {@code this} matcher. 059 * 060 * @return the underlying tree pattern 061 */ 062 public TreePattern<V> pattern() { 063 return _pattern; 064 } 065 066 /** 067 * Return the matching tree. 068 * 069 * @return the matching tree 070 */ 071 public Tree<V, ?> tree() { 072 return _tree; 073 } 074 075 /** 076 * Tests if the tree matches the pattern. 077 * 078 * @return {@code true} if the tree matches against the pattern, 079 * {@code false} otherwise 080 * @throws NullPointerException if the given predicate is {@code null} 081 */ 082 public boolean matches() { 083 return _pattern.matches(_tree); 084 } 085 086 /** 087 * Return all matching <em>sub</em>-trees. 088 * 089 * @return all matching subtrees 090 * @throws NullPointerException if the given predicate is {@code null} 091 */ 092 public Stream<TreeMatchResult<V>> results() { 093 return _tree.stream() 094 .flatMap(tree -> _pattern.match(tree).stream()); 095 } 096 097 static <V> TreeMatcher<V> of( 098 final TreePattern<V> pattern, 099 final Tree<V, ?> tree 100 ) { 101 return new TreeMatcher<>(pattern, tree); 102 } 103 104}