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