Package ro.redeul.google.go.lang.psi.impl.expressions.primary

Source Code of ro.redeul.google.go.lang.psi.impl.expressions.primary.GoBuiltinCallOrConversionExpressionImpl

package ro.redeul.google.go.lang.psi.impl.expressions.primary;

import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Condition;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import ro.redeul.google.go.lang.psi.GoFile;
import ro.redeul.google.go.lang.psi.expressions.GoExpr;
import ro.redeul.google.go.lang.psi.expressions.primary.GoBuiltinCallOrConversionExpression;
import ro.redeul.google.go.lang.psi.toplevel.GoFunctionDeclaration;
import ro.redeul.google.go.lang.psi.toplevel.GoPackageDeclaration;
import ro.redeul.google.go.lang.psi.types.GoPsiType;
import ro.redeul.google.go.lang.psi.types.GoPsiTypeMap;
import ro.redeul.google.go.lang.psi.types.GoPsiTypeSlice;
import ro.redeul.google.go.lang.psi.typing.*;
import ro.redeul.google.go.lang.psi.visitors.GoElementVisitor;
import ro.redeul.google.go.lang.stubs.GoNamesCache;

import static com.intellij.patterns.PlatformPatterns.psiElement;
import static com.intellij.patterns.StandardPatterns.string;
import static ro.redeul.google.go.lang.psi.typing.GoTypes.Builtin.*;
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.resolveSafely;

/**
* Author: Toader Mihai Claudiu <mtoader@gmail.com>
* <p/>
* Date: 6/2/11
* Time: 3:58 AM
*/
public class GoBuiltinCallOrConversionExpressionImpl extends GoCallOrConvExpressionImpl
        implements GoBuiltinCallOrConversionExpression {

    private static final ElementPattern<GoFunctionDeclaration> BUILTIN_FUNCTION =
            psiElement(GoFunctionDeclaration.class)
                    .withParent(
                            psiElement(GoFile.class)
                                    .withChild(
                                            psiElement(GoPackageDeclaration.class)
                                                    .withText(
                                                            string().endsWith("builtin"))
                                    )
                    );

    public GoBuiltinCallOrConversionExpressionImpl(@NotNull ASTNode node) {
        super(node);
    }

    @NotNull
    @Override
    protected GoType[] resolveTypes() {
        GoType[] baseExprType = getBaseExpression().getType();

        if ( baseExprType.length != 1 )
            return GoType.EMPTY_ARRAY;

        if ( baseExprType[0] instanceof GoTypeFunction )
            return processBuiltinFunction(((GoTypeFunction) baseExprType[0]).getPsiType().getName());

        if ( baseExprType[0] instanceof GoTypePrimitive ) {
            GoTypePrimitive castType = (GoTypePrimitive) baseExprType[0];

            GoExpr[] arguments = getArguments();
            if ( arguments.length != 1 )
                return baseExprType;

            GoType[] argumentType = arguments[0].getType();
            if (argumentType.length != 1 || !(argumentType[0] instanceof GoTypeConstant) )
                return baseExprType;

            GoTypeConstant constantArgument = (GoTypeConstant) argumentType[0];
            if ( castType.canRepresent(constantArgument)) {
                return new GoType[] { constantArgument.retypeAs(castType)};
            }

            return new GoType[]{castType};
        }

        return GoType.EMPTY_ARRAY;
    }

    @Override
    public GoPsiType[] getArgumentsType() {
        PsiElement reference = resolveSafely(getBaseExpression(),
                PsiElement.class);

        if (reference == null) {
            return processArgumentsType(this.getBaseExpression().getText());
        }

        if (reference.getParent() instanceof GoFunctionDeclaration) {
            GoFunctionDeclaration declaration =
                    (GoFunctionDeclaration) reference.getParent();

            if (BUILTIN_FUNCTION.accepts(declaration))
                return processArgumentsType(declaration.getFunctionName());
        }

        return GoPsiType.EMPTY_ARRAY;
    }

    private GoPsiType[] processArgumentsType(String functionName) {
        GoExpr[] args = getArguments();

        if (functionName.equals("append")) {
            if (args.length > 1) {
                GoType[] types = args[0].getType();
                if (types.length > 0 && types[0] instanceof GoTypeSlice) {
                    GoPsiTypeSlice appendedSlice = ((GoTypeSlice) types[0]).getPsiType();
                    GoPsiType[] result = new GoPsiType[args.length];
                    result[0] = appendedSlice;
                    if (isCallWithVariadicParameter()){
                        result[1] = appendedSlice;
                        return result;
                    }
                    GoPsiType elem = appendedSlice.getElementType();
                    for (int i = 1; i < args.length; i++) {
                        result[i] = elem;
                    }
                    return result;
                }
            }
        } else if (functionName.equals("copy")) {
            if (args.length == 2) {
                GoType[] types = args[0].getType();
                if (types.length > 0 && types[0] instanceof GoTypeSlice) {
                    GoPsiTypeSlice copiedSlice = ((GoTypeSlice) types[0]).getPsiType();
                    return new GoPsiType[]{copiedSlice, copiedSlice};
                }
            }
        } else if (functionName.equals("delete")) {
            if (args.length == 2) {
                GoType[] types = args[0].getType();
                if (types.length > 0 && types[0] instanceof GoTypeMap) {
                    GoPsiTypeMap map = ((GoTypeMap) types[0]).getPsiType();
                    return new GoPsiType[]{map, map.getKeyType()};
                }
            }
        }

        return GoPsiType.EMPTY_ARRAY;
    }

    @NotNull
    private GoType[] processBuiltinFunction(String functionName) {

        GoNamesCache namesCache = GoNamesCache.getInstance(getProject());

        GoExpr[] args = getArguments();
        GoPsiType typeArg = getTypeArgument();

        if (functionName.equals("new")) {
            if (typeArg != null) {
                return new GoType[]{
                        GoTypes.makePointer(typeArg)
                };
            }
        } else if (functionName.matches("^(len|cap|copy)$")) {
            return new GoType[]{types().getBuiltin(Int)};
        } else if (functionName.equals("complex")) {
            if (args.length > 0) {
                if (hasBuiltinType(args[0].getType(), Float64))
                    return new GoType[]{types().getBuiltin(Complex128)};

                if (hasBuiltinType(args[0].getType(), Float32))
                    return new GoType[]{types().getBuiltin(Complex64)};

//                if (hasBuiltinType(args[0].getType(), Int))
//                    return new GoType[]{types().getBuiltin(Complex128)};
            }
        } else if (functionName.matches("^(real|imag)$")) {
            if (args.length > 0) {
                if (hasBuiltinType(args[0].getType(), Complex128))
                    return new GoType[]{types().getBuiltin(Float64)};

                if (hasBuiltinType(args[0].getType(), Complex64))
                    return new GoType[]{types().getBuiltin(Float32)};
            }
        } else if (functionName.equals("make")) {
            if (typeArg != null)
                return new GoType[]{types().fromPsiType(typeArg)};
        } else if (functionName.equals("append")) {
            if (args.length > 1) {
                GoType[] types = args[0].getType();
                if (types.length > 0) {
                    return new GoType[]{types[0]};
                }
            }
        }

        return GoType.EMPTY_ARRAY;
    }

    private boolean hasBuiltinType(GoType[] types, final GoTypes.Builtin builtin) {
        return ContainerUtil.find(types, new Condition<GoType>() {
            @Override
            public boolean value(GoType goType) {
                if ( goType.isIdentical(types().getBuiltin(builtin)) )
                    return true;

                if ( goType instanceof GoTypeConstant ) {
                    GoTypeConstant typeConstant = (GoTypeConstant) goType;
                    return GoTypes.getInstance(getProject()).getBuiltin(builtin).canRepresent(typeConstant);
                }

                return false;
            }
        }) != null;
    }

    @Override
    public void accept(GoElementVisitor visitor) {
        visitor.visitBuiltinCallExpression(this);
    }
}
TOP

Related Classes of ro.redeul.google.go.lang.psi.impl.expressions.primary.GoBuiltinCallOrConversionExpressionImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.