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