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.AnnotationDescriptor;
021    import org.jetbrains.jet.lang.descriptors.impl.*;
022    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
023    import org.jetbrains.jet.lang.resolve.name.Name;
024    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
025    import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
026    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
027    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
028    import org.jetbrains.jet.lang.resolve.scopes.receivers.ScriptReceiver;
029    import org.jetbrains.jet.lang.types.JetType;
030    import org.jetbrains.jet.lang.types.TypeSubstitutor;
031    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032    
033    import java.util.Collections;
034    import java.util.HashSet;
035    import java.util.List;
036    
037    public class ScriptDescriptor extends DeclarationDescriptorNonRootImpl {
038        public static final String LAST_EXPRESSION_VALUE_FIELD_NAME = "rv";
039        private static final Name NAME = Name.special("<script>");
040    
041        private final int priority;
042    
043        private JetType returnType;
044        private List<ValueParameterDescriptor> valueParameters;
045    
046        private final ScriptCodeDescriptor scriptCodeDescriptor = new ScriptCodeDescriptor(this);
047        private final ReceiverParameterDescriptor implicitReceiver = new ReceiverParameterDescriptorImpl(this,
048                                                                                                         // Putting Any here makes no sense,
049                                                                                                         // it is simply copied from someplace else
050                                                                                                         // during a refactoring
051                                                                                                         KotlinBuiltIns.getInstance().getAnyType(),
052                                                                                                         new ScriptReceiver(this));
053    
054        private final ClassDescriptorImpl classDescriptor;
055    
056        private final WritableScopeImpl classScope;
057    
058        public ScriptDescriptor(
059                @NotNull DeclarationDescriptor containingDeclaration,
060                int priority,
061                @NotNull JetScope scriptScope,
062                @NotNull Name className
063        ) {
064            super(containingDeclaration, Collections.<AnnotationDescriptor>emptyList(), NAME);
065            this.priority = priority;
066    
067            classDescriptor = new ClassDescriptorImpl(
068                    containingDeclaration,
069                    Collections.<AnnotationDescriptor>emptyList(),
070                    Modality.FINAL,
071                    className);
072            classScope = new WritableScopeImpl(scriptScope, containingDeclaration, RedeclarationHandler.DO_NOTHING, "script members");
073            classScope.changeLockLevel(WritableScope.LockLevel.BOTH);
074            classDescriptor.initialize(
075                    false,
076                    Collections.<TypeParameterDescriptor>emptyList(),
077                    Collections.singletonList(KotlinBuiltIns.getInstance().getAnyType()),
078                    classScope,
079                    new HashSet<ConstructorDescriptor>(),
080                    null,
081                    false);
082        }
083    
084        public void initialize(
085                @NotNull JetType returnType,
086                @NotNull List<? extends PropertyDescriptorImpl> properties,
087                @NotNull List<? extends FunctionDescriptor> functions
088        ) {
089            this.returnType = returnType;
090            scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
091    
092            PropertyDescriptorImpl propertyDescriptor = new PropertyDescriptorImpl(classDescriptor,
093                                                                   Collections.<AnnotationDescriptor>emptyList(),
094                                                                   Modality.FINAL,
095                                                                   Visibilities.PUBLIC,
096                                                                   false,
097                                                                   Name.identifier(LAST_EXPRESSION_VALUE_FIELD_NAME),
098                                                                   CallableMemberDescriptor.Kind.DECLARATION);
099            propertyDescriptor.setType(
100                    returnType,
101                    Collections.<TypeParameterDescriptor>emptyList(),
102                    classDescriptor.getThisAsReceiverParameter(),
103                    ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
104            propertyDescriptor.initialize(null, null);
105            classScope.addPropertyDescriptor(propertyDescriptor);
106    
107            for (PropertyDescriptorImpl property : properties) {
108                initializeWithDefaultGetterSetter(property);
109                classScope.addPropertyDescriptor(property);
110            }
111    
112            for (FunctionDescriptor function : functions) {
113                classScope.addFunctionDescriptor(function);
114            }
115        }
116    
117        public static void initializeWithDefaultGetterSetter(PropertyDescriptorImpl propertyDescriptor) {
118            PropertyGetterDescriptorImpl getter = propertyDescriptor.getGetter();
119            if (getter == null && propertyDescriptor.getVisibility() != Visibilities.PRIVATE) {
120                getter = DescriptorFactory.createDefaultGetter(propertyDescriptor);
121                getter.initialize(propertyDescriptor.getType());
122            }
123    
124            PropertySetterDescriptor setter = propertyDescriptor.getSetter();
125            if (setter == null && propertyDescriptor.isVar()) {
126                setter = DescriptorFactory.createDefaultSetter(propertyDescriptor);
127            }
128            propertyDescriptor.initialize(getter, setter);
129        }
130    
131        public int getPriority() {
132            return priority;
133        }
134    
135        @NotNull
136        public JetType getReturnType() {
137            return returnType;
138        }
139    
140        @NotNull
141        public List<ValueParameterDescriptor> getValueParameters() {
142            return valueParameters;
143        }
144    
145        @NotNull
146        public ScriptCodeDescriptor getScriptCodeDescriptor() {
147            return scriptCodeDescriptor;
148        }
149    
150        @NotNull
151        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
152            return implicitReceiver;
153        }
154    
155        @Override
156        public DeclarationDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
157            throw new IllegalStateException("nothing to substitute in script");
158        }
159    
160        @Override
161        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
162            return visitor.visitScriptDescriptor(this, data);
163        }
164    
165        public void setValueParameters(@NotNull List<ValueParameterDescriptor> valueParameters) {
166            this.valueParameters = valueParameters;
167            ConstructorDescriptorImpl constructorDescriptor =
168                    new ConstructorDescriptorImpl(classDescriptor, Collections.<AnnotationDescriptor>emptyList(), true)
169                            .initialize(Collections.<TypeParameterDescriptor>emptyList(), valueParameters, Visibilities.PUBLIC);
170            constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
171    
172            classDescriptor.getConstructors().add(constructorDescriptor);
173            classDescriptor.setPrimaryConstructor(constructorDescriptor);
174    
175            for (ValueParameterDescriptor parameter : valueParameters) {
176                PropertyDescriptorImpl propertyDescriptor = new PropertyDescriptorImpl(classDescriptor,
177                                                                       Collections.<AnnotationDescriptor>emptyList(),
178                                                                       Modality.FINAL,
179                                                                       Visibilities.PUBLIC,
180                                                                       false,
181                                                                       parameter.getName(),
182                                                                       CallableMemberDescriptor.Kind.DECLARATION);
183                propertyDescriptor.setType(
184                        parameter.getType(),
185                        Collections.<TypeParameterDescriptor>emptyList(),
186                        classDescriptor.getThisAsReceiverParameter(), ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER);
187                //PropertyGetterDescriptor getter = DescriptorResolver.createDefaultGetter(propertyDescriptor);
188                //getter.initialize(propertyDescriptor.getType());
189                propertyDescriptor.initialize(null, null);
190                classScope.addPropertyDescriptor(propertyDescriptor);
191            }
192        }
193    
194        @NotNull
195        public ClassDescriptor getClassDescriptor() {
196            return classDescriptor;
197        }
198    }