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.impl;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.jet.lang.descriptors.*;
021    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
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        private PropertyDescriptor scriptResultProperty;
055    
056        public ScriptDescriptorImpl(
057                @NotNull DeclarationDescriptor containingDeclaration,
058                int priority,
059                @NotNull JetScope scriptScope,
060                @NotNull Name className,
061                @NotNull SourceElement source
062        ) {
063            super(containingDeclaration, Annotations.EMPTY, NAME, source);
064            this.priority = priority;
065    
066            classDescriptor = new MutableClassDescriptor(containingDeclaration, scriptScope, ClassKind.CLASS,
067                                                         false, className, SourceElement.NO_SOURCE);
068            classDescriptor.addSupertype(KotlinBuiltIns.getInstance().getAnyType());
069            classDescriptor.setModality(Modality.FINAL);
070            classDescriptor.setVisibility(Visibilities.PUBLIC);
071            classDescriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
072    
073            classScope = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, RedeclarationHandler.DO_NOTHING, "script members");
074            classScope.changeLockLevel(WritableScope.LockLevel.BOTH);
075            classDescriptor.setScopeForMemberLookup(classScope);
076            classDescriptor.createTypeConstructor();
077        }
078    
079        public void initialize(
080                @NotNull JetType returnType,
081                @NotNull List<? extends PropertyDescriptorImpl> properties,
082                @NotNull List<? extends FunctionDescriptor> functions
083        ) {
084            assert valueParameters != null : "setValueParameters() must be called before this method";
085            scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
086    
087            scriptResultProperty = createScriptResultProperty(this);
088            classScope.addPropertyDescriptor(scriptResultProperty);
089    
090            for (PropertyDescriptorImpl property : properties) {
091                classScope.addPropertyDescriptor(property);
092            }
093    
094            for (FunctionDescriptor function : functions) {
095                classScope.addFunctionDescriptor(function);
096            }
097        }
098    
099        @NotNull
100        public static PropertyDescriptor createScriptResultProperty(@NotNull ScriptDescriptor scriptDescriptor) {
101            PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(scriptDescriptor.getClassDescriptor(),
102                                                                                      Annotations.EMPTY,
103                                                                                      Modality.FINAL,
104                                                                                      Visibilities.PUBLIC,
105                                                                                      false,
106                                                                                      Name.identifier(LAST_EXPRESSION_VALUE_FIELD_NAME),
107                                                                                      CallableMemberDescriptor.Kind.DECLARATION,
108                                                                                      SourceElement.NO_SOURCE);
109            JetType returnType = scriptDescriptor.getScriptCodeDescriptor().getReturnType();
110            assert returnType != null : "Return type not initialized for " + scriptDescriptor;
111            propertyDescriptor.setType(
112                    returnType,
113                    Collections.<TypeParameterDescriptor>emptyList(),
114                    scriptDescriptor.getThisAsReceiverParameter(),
115                    ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
116            propertyDescriptor.initialize(null, null);
117            return propertyDescriptor;
118        }
119    
120        @NotNull
121        @Override
122        public PropertyDescriptor getScriptResultProperty() {
123            return scriptResultProperty;
124        }
125    
126        @Override
127        public int getPriority() {
128            return priority;
129        }
130    
131        @Override
132        @NotNull
133        public ScriptCodeDescriptor getScriptCodeDescriptor() {
134            return scriptCodeDescriptor;
135        }
136    
137        @Override
138        @NotNull
139        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
140            return implicitReceiver;
141        }
142    
143        @Override
144        public DeclarationDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
145            throw new IllegalStateException("nothing to substitute in script");
146        }
147    
148        @Override
149        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
150            return visitor.visitScriptDescriptor(this, data);
151        }
152    
153        public void setValueParameters(@NotNull List<ValueParameterDescriptor> valueParameters) {
154            this.valueParameters = valueParameters;
155    
156            ConstructorDescriptorImpl constructorDescriptor = createConstructor(this, valueParameters);
157            constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
158            classDescriptor.getConstructors().add(constructorDescriptor);
159            classDescriptor.setPrimaryConstructor(constructorDescriptor);
160    
161            for (ValueParameterDescriptor valueParameter : valueParameters) {
162                classScope.addPropertyDescriptor(createPropertyFromScriptParameter(this, valueParameter));
163            }
164        }
165    
166        @NotNull
167        public static ConstructorDescriptorImpl createConstructor(
168                @NotNull ScriptDescriptor scriptDescriptor, @NotNull List<ValueParameterDescriptor> valueParameters
169        ) {
170            return ConstructorDescriptorImpl.create(scriptDescriptor.getClassDescriptor(), Annotations.EMPTY, true, SourceElement.NO_SOURCE)
171                    .initialize(
172                            Collections.<TypeParameterDescriptor>emptyList(),
173                            valueParameters,
174                            Visibilities.PUBLIC,
175                            false
176                    );
177        }
178    
179        @NotNull
180        public static PropertyDescriptor createPropertyFromScriptParameter(
181                @NotNull ScriptDescriptor scriptDescriptor,
182                @NotNull ValueParameterDescriptor parameter
183        ) {
184            PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
185                    scriptDescriptor.getClassDescriptor(),
186                    Annotations.EMPTY,
187                    Modality.FINAL,
188                    Visibilities.PUBLIC,
189                    false,
190                    parameter.getName(),
191                    CallableMemberDescriptor.Kind.DECLARATION,
192                    SourceElement.NO_SOURCE
193            );
194            propertyDescriptor.setType(
195                    parameter.getType(),
196                    Collections.<TypeParameterDescriptor>emptyList(),
197                    scriptDescriptor.getThisAsReceiverParameter(), ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
198            propertyDescriptor.initialize(null, null);
199            return propertyDescriptor;
200        }
201    
202        @Override
203        @NotNull
204        public ClassDescriptor getClassDescriptor() {
205            return classDescriptor;
206        }
207    
208        @Override
209        @NotNull
210        public WritableScope getScopeForBodyResolution() {
211            return scopeForBodyResolution;
212        }
213    
214        public void setScopeForBodyResolution(@NotNull WritableScope scopeForBodyResolution) {
215            assert this.scopeForBodyResolution == null : "Scope for body resolution already set for " + this;
216            this.scopeForBodyResolution = scopeForBodyResolution;
217        }
218    }