1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.impl;
7   
8   import java.util.List;
9   
10  import dev.metaschema.core.metapath.DynamicContext;
11  import dev.metaschema.core.metapath.IExpression;
12  import dev.metaschema.core.metapath.IMetapathExpression;
13  import dev.metaschema.core.metapath.InvalidMetapathGrammarException;
14  import dev.metaschema.core.metapath.MetapathException;
15  import dev.metaschema.core.metapath.StaticContext;
16  import dev.metaschema.core.metapath.cst.IExpressionVisitor;
17  import dev.metaschema.core.metapath.item.IItem;
18  import dev.metaschema.core.metapath.item.ISequence;
19  import dev.metaschema.core.util.ObjectUtils;
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  import nl.talsmasoftware.lazy4j.Lazy;
22  
23  /**
24   * An implementation of a Metapath expression that is compiled when evaluated.
25   * <p>
26   * Lazy compilation may cause additional {@link MetapathException} errors at
27   * evaluation time, since compilation errors are not raised until evaluation.
28   */
29  public class LazyCompilationMetapathExpression implements IMetapathExpression {
30    @NonNull
31    private final String path;
32    @NonNull
33    private final StaticContext staticContext;
34    @NonNull
35    private final Lazy<IMetapathExpression> compiledMetapath;
36  
37    /**
38     * Construct a new lazy-compiled Metapath expression.
39     *
40     * @param path
41     *          the metapath expression
42     * @param staticContext
43     *          the static evaluation context
44     */
45    public LazyCompilationMetapathExpression(
46        @NonNull String path,
47        @NonNull StaticContext staticContext) {
48      this.path = path;
49      this.staticContext = staticContext;
50      this.compiledMetapath = ObjectUtils.notNull(Lazy.of(() -> {
51        IMetapathExpression result;
52        try {
53          result = IMetapathExpression.compile(path, staticContext);
54        } catch (InvalidMetapathGrammarException ex) {
55          throw new InvalidMetapathGrammarException(ex);
56        }
57        return result;
58      }));
59    }
60  
61    @Override
62    public String getPath() {
63      return path;
64    }
65  
66    @Override
67    public StaticContext getStaticContext() {
68      return staticContext;
69    }
70  
71    @NonNull
72    private IMetapathExpression getCompiledMetapath() {
73      return ObjectUtils.notNull(compiledMetapath.get());
74    }
75  
76    @Override
77    public List<? extends IExpression> getChildren() {
78      return getCompiledMetapath().getChildren();
79    }
80  
81    @Override
82    public Class<? extends IItem> getBaseResultType() {
83      return getCompiledMetapath().getBaseResultType();
84    }
85  
86    @Override
87    public ISequence<? extends IItem> accept(DynamicContext dynamicContext, ISequence<?> focus) {
88      return getCompiledMetapath().accept(dynamicContext, focus);
89    }
90  
91    @Override
92    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
93      return getCompiledMetapath().accept(visitor, context);
94    }
95  
96    @Override
97    public <T extends IItem> ISequence<T> evaluate(IItem focus, DynamicContext dynamicContext) {
98      return getCompiledMetapath().evaluate(focus, dynamicContext);
99    }
100 
101   @Override
102   public String toString() {
103     return getPath();
104   }
105 }