Home | History | Annotate | Download | only in lookup
      1 /*
      2  * Copyright 2017 Google Inc. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.turbine.binder.lookup;
     18 
     19 import com.google.turbine.binder.sym.ClassSymbol;
     20 import com.google.turbine.diag.SourceFile;
     21 import com.google.turbine.diag.TurbineError;
     22 import com.google.turbine.diag.TurbineError.ErrorKind;
     23 
     24 /**
     25  * A scope for imports. Non-canonical imports depend on hierarchy analysis, so to break the cycle we
     26  * defer non-canonical resolution to a {@link ResolveFunction} that is provided once hierarchy
     27  * analysis is underway.
     28  */
     29 public interface ImportScope {
     30 
     31   /**
     32    * A function that performs non-canonical resolution, see {@link
     33    * com.google.turbine.binder.Resolve#resolve}.
     34    */
     35   @FunctionalInterface
     36   interface ResolveFunction {
     37 
     38     ClassSymbol resolveOne(ClassSymbol base, String name);
     39 
     40     default ClassSymbol resolve(SourceFile source, int position, LookupResult result) {
     41       ClassSymbol sym = (ClassSymbol) result.sym();
     42       for (String bit : result.remaining()) {
     43         sym = resolveOne(sym, bit);
     44         if (sym == null) {
     45           throw TurbineError.format(source, position, ErrorKind.SYMBOL_NOT_FOUND, bit);
     46         }
     47       }
     48       return sym;
     49     }
     50   }
     51 
     52   /** See {@link Scope#lookup(LookupKey)}. */
     53   LookupResult lookup(LookupKey lookupKey, ResolveFunction resolve);
     54 
     55   /** Adds a scope to the chain, in the manner of {@link CompoundScope#append(Scope)}. */
     56   default ImportScope append(ImportScope next) {
     57     return new ImportScope() {
     58       @Override
     59       public LookupResult lookup(LookupKey lookupKey, ResolveFunction resolve) {
     60         LookupResult result = next.lookup(lookupKey, resolve);
     61         if (result != null) {
     62           return result;
     63         }
     64         return ImportScope.this.lookup(lookupKey, resolve);
     65       }
     66     };
     67   }
     68 
     69   /**
     70    * Creates a trivial {@link ImportScope} from a {@link Scope}, which ignores the provided {@link
     71    * ResolveFunction} and calls the underlying scope's lookup method. Used to chain {@link Scope}s
     72    * and {@link ImportScope}s together.
     73    */
     74   static ImportScope fromScope(Scope scope) {
     75     return new ImportScope() {
     76       @Override
     77       public LookupResult lookup(LookupKey lookupKey, ResolveFunction resolve) {
     78         return scope.lookup(lookupKey);
     79       }
     80     };
     81   }
     82 
     83   /** Partially applies the given {@link ResolveFunction} to this {@link ImportScope}. */
     84   default CompoundScope toScope(ResolveFunction resolve) {
     85     return CompoundScope.base(
     86         new Scope() {
     87           @Override
     88           public LookupResult lookup(LookupKey lookupKey) {
     89             return ImportScope.this.lookup(lookupKey, resolve);
     90           }
     91         });
     92   }
     93 }
     94