001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.descriptors;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
021    import org.jetbrains.jet.lang.descriptors.impl.*;
022    import org.jetbrains.jet.lang.resolve.name.Name;
023    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
024    import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
025    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
026    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
027    import org.jetbrains.jet.lang.resolve.scopes.receivers.ScriptReceiver;
028    import org.jetbrains.jet.lang.types.JetType;
029    import org.jetbrains.jet.lang.types.TypeSubstitutor;
030    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
031    
032    import java.util.Collections;
033    import java.util.List;
034    
035    // SCRIPT: Script declaration descriptor
036    public class ScriptDescriptorImpl extends DeclarationDescriptorNonRootImpl implements ScriptDescriptor {
037    
038        private final int priority;
039    
040        private List<ValueParameterDescriptor> valueParameters;
041    
042        private final ScriptCodeDescriptor scriptCodeDescriptor = new ScriptCodeDescriptor(this);
043        private final ReceiverParameterDescriptor implicitReceiver = new ReceiverParameterDescriptorImpl(this,
044                                                                                                         // Putting Any here makes no sense,
045                                                                                                         // it is simply copied from someplace else
046                                                                                                         // during a refactoring
047                                                                                                         KotlinBuiltIns.getInstance().getAnyType(),
048                                                                                                         new ScriptReceiver(this));
049    
050        private final MutableClassDescriptor classDescriptor;
051    
052        private final WritableScopeImpl classScope;
053        private WritableScope scopeForBodyResolution;
054    
055        public ScriptDescriptorImpl(
056                @NotNull DeclarationDescriptor containingDeclaration,
057                int priority,
058                @NotNull JetScope scriptScope,
059                @NotNull Name className
060        ) {
061            super(containingDeclaration, Annotations.EMPTY, NAME);
062            this.priority = priority;
063    
064            classDescriptor = new MutableClassDescriptor(containingDeclaration, scriptScope, ClassKind.CLASS, false, className);
065            classDescriptor.addSupertype(KotlinBuiltIns.getInstance().getAnyType());
066            classDescriptor.setModality(Modality.FINAL);
067            classDescriptor.setVisibility(Visibilities.PUBLIC);
068            classDescriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
069    
070            classScope = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, RedeclarationHandler.DO_NOTHING, "script members");
071            classScope.changeLockLevel(WritableScope.LockLevel.BOTH);
072            classDescriptor.setScopeForMemberLookup(classScope);
073            classDescriptor.createTypeConstructor();
074        }
075    
076        public void initialize(
077                @NotNull JetType returnType,
078                @NotNull List<? extends PropertyDescriptorImpl> properties,
079                @NotNull List<? extends FunctionDescriptor> functions
080        ) {
081            assert valueParameters != null : "setValueParameters() must be called before this method";
082            scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
083    
084            classScope.addPropertyDescriptor(createScriptResultProperty(this));
085    
086            for (PropertyDescriptorImpl property : properties) {
087                classScope.addPropertyDescriptor(property);
088            }
089    
090            for (FunctionDescriptor function : functions) {
091                classScope.addFunctionDescriptor(function);
092            }
093        }
094    
095        @NotNull
096        public static PropertyDescriptor createScriptResultProperty(@NotNull ScriptDescriptor scriptDescriptor) {
097            PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(scriptDescriptor.getClassDescriptor(),
098                                                                                      Annotations.EMPTY,
099                                                                                      Modality.FINAL,
100                                                                                      Visibilities.PUBLIC,
101                                                                                      false,
102                                                                                      Name.identifier(LAST_EXPRESSION_VALUE_FIELD_NAME),
103                                                                                      CallableMemberDescriptor.Kind.DECLARATION);
104            JetType returnType = scriptDescriptor.getScriptCodeDescriptor().getReturnType();
105            assert returnType != null : "Return type not initialized for " + scriptDescriptor;
106            propertyDescriptor.setType(
107                    returnType,
108                    Collections.<TypeParameterDescriptor>emptyList(),
109                    scriptDescriptor.getThisAsReceiverParameter(),
110                    ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
111            propertyDescriptor.initialize(null, null);
112            return propertyDescriptor;
113        }
114    
115        @Override
116        public int getPriority() {
117            return priority;
118        }
119    
120        @Override
121        @NotNull
122        public ScriptCodeDescriptor getScriptCodeDescriptor() {
123            return scriptCodeDescriptor;
124        }
125    
126        @Override
127        @NotNull
128        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
129            return implicitReceiver;
130        }
131    
132        @Override
133        public DeclarationDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
134            throw new IllegalStateException("nothing to substitute in script");
135        }
136    
137        @Override
138        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
139            return visitor.visitScriptDescriptor(this, data);
140        }
141    
142        public void setValueParameters(@NotNull List<ValueParameterDescriptor> valueParameters) {
143            this.valueParameters = valueParameters;
144    
145            ConstructorDescriptorImpl constructorDescriptor = createConstructor(this, valueParameters);
146            constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
147            classDescriptor.getConstructors().add(constructorDescriptor);
148            classDescriptor.setPrimaryConstructor(constructorDescriptor);
149    
150            for (ValueParameterDescriptor valueParameter : valueParameters) {
151                classScope.addPropertyDescriptor(createPropertyFromScriptParameter(this, valueParameter));
152            }
153        }
154    
155        @NotNull
156        public static ConstructorDescriptorImpl createConstructor(
157                @NotNull ScriptDescriptor scriptDescriptor, @NotNull List<ValueParameterDescriptor> valueParameters
158        ) {
159            return ConstructorDescriptorImpl.create(scriptDescriptor.getClassDescriptor(), Annotations.EMPTY, true)
160                    .initialize(
161                            Collections.<TypeParameterDescriptor>emptyList(),
162                            valueParameters,
163                            Visibilities.PUBLIC,
164                            false
165                    );
166        }
167    
168        @NotNull
169        public static PropertyDescriptor createPropertyFromScriptParameter(
170                @NotNull ScriptDescriptor scriptDescriptor,
171                @NotNull ValueParameterDescriptor parameter
172        ) {
173            PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(scriptDescriptor.getClassDescriptor(),
174                                                                                      Annotations.EMPTY,
175                                                                                      Modality.FINAL,
176                                                                                      Visibilities.PUBLIC,
177                                                                                      false,
178                                                                                      parameter.getName(),
179                                                                                      CallableMemberDescriptor.Kind.DECLARATION);
180            propertyDescriptor.setType(
181                    parameter.getType(),
182                    Collections.<TypeParameterDescriptor>emptyList(),
183                    scriptDescriptor.getThisAsReceiverParameter(), ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
184            propertyDescriptor.initialize(null, null);
185            return propertyDescriptor;
186        }
187    
188        @Override
189        @NotNull
190        public ClassDescriptor getClassDescriptor() {
191            return classDescriptor;
192        }
193    
194        @Override
195        @NotNull
196        public WritableScope getScopeForBodyResolution() {
197            return scopeForBodyResolution;
198        }
199    
200        public void setScopeForBodyResolution(@NotNull WritableScope scopeForBodyResolution) {
201            assert this.scopeForBodyResolution == null : "Scope for body resolution already set for " + this;
202            this.scopeForBodyResolution = scopeForBodyResolution;
203        }
204    }