/* * Copyright 2013-2017 consulo.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package consulo.csharp.lang.psi.impl.source; import java.math.BigInteger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.ContributedReferenceHost; import com.intellij.psi.LiteralTextEscaper; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLanguageInjectionHost; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiReferenceService; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.tree.IElementType; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.psi.CSharpElementVisitor; import consulo.csharp.lang.psi.CSharpTokenSets; import consulo.csharp.lang.psi.CSharpTokens; import consulo.csharp.lang.psi.CSharpTokensImpl; import consulo.csharp.lang.psi.impl.source.injection.CSharpStringLiteralEscaper; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpConstantTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpNullTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpTypeRefByQName; import consulo.dotnet.DotNetTypes; import consulo.dotnet.psi.DotNetConstantExpression; import consulo.dotnet.psi.DotNetVariable; import consulo.dotnet.resolve.DotNetTypeRef; /** * @author VISTALL * @since 16.12.13. */ public class CSharpConstantExpressionImpl extends CSharpExpressionImpl implements DotNetConstantExpression, PsiLanguageInjectionHost, ContributedReferenceHost { public CSharpConstantExpressionImpl(@NotNull ASTNode node) { super(node); } @Override public void accept(@NotNull CSharpElementVisitor visitor) { visitor.visitConstantExpression(this); } @RequiredReadAction @NotNull @Override public DotNetTypeRef toTypeRefImpl(boolean resolveFromParent) { IElementType elementType = getLiteralType(); PsiElement parent = getParent(); if(parent instanceof DotNetVariable) { DotNetTypeRef typeRef = ((DotNetVariable) parent).toTypeRef(false); if(typeRef == DotNetTypeRef.AUTO_TYPE) { if(elementType == CSharpTokens.INTEGER_LITERAL) { CSharpTypeRefByQName another = new CSharpTypeRefByQName(this, DotNetTypes.System.Int32); if(CSharpConstantTypeRef.testNumberConstant(this, "", another, this) != null) { return another; } another = new CSharpTypeRefByQName(this, DotNetTypes.System.Int64); if(CSharpConstantTypeRef.testNumberConstant(this, "", another, this) != null) { return another; } return DotNetTypeRef.ERROR_TYPE; } } } DotNetTypeRef defaultConstantTypeRef = getDefaultConstantTypeRef(); if(defaultConstantTypeRef != null) { return defaultConstantTypeRef; } else { throw new UnsupportedOperationException(elementType.toString()); } } @RequiredReadAction @Nullable public DotNetTypeRef getDefaultConstantTypeRef() { IElementType elementType = getLiteralType(); if(elementType == CSharpTokens.INTEGER_LITERAL) { return new CSharpConstantTypeRef(this, new CSharpTypeRefByQName(this, DotNetTypes.System.Int32)); } else if(elementType == CSharpTokens.DOUBLE_LITERAL) { String text = this.getText(); // explicit type if(text.endsWith("d") || text.endsWith("D")) { return new CSharpConstantTypeRef(this, new CSharpTypeRefByQName(this, DotNetTypes.System.Double)); } return new CSharpConstantTypeRef(this, new CSharpTypeRefByQName(this, DotNetTypes.System.Double)); } else if(elementType == CSharpTokens.STRING_LITERAL || elementType == CSharpTokens.VERBATIM_STRING_LITERAL || elementType == CSharpTokensImpl.INTERPOLATION_STRING_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.String); } else if(elementType == CSharpTokens.CHARACTER_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.Char); } else if(elementType == CSharpTokens.UINTEGER_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.UInt32); } else if(elementType == CSharpTokens.ULONG_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.UInt64); } else if(elementType == CSharpTokens.LONG_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.Int64); } else if(elementType == CSharpTokens.FLOAT_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.Single); } else if(elementType == CSharpTokens.DECIMAL_LITERAL) { return new CSharpTypeRefByQName(this, DotNetTypes.System.Decimal); } else if(elementType == CSharpTokens.NULL_LITERAL) { return new CSharpNullTypeRef(this); } else if(elementType == CSharpTokens.TRUE_KEYWORD || elementType == CSharpTokens.FALSE_KEYWORD) { return new CSharpTypeRefByQName(this, DotNetTypes.System.Boolean); } return null; } @Nullable @RequiredReadAction public Object getValue(@NotNull String prefix) { PsiElement byType = getFirstChild(); assert byType != null; IElementType elementType = getLiteralType(); String text = prefix.isEmpty() ? getText() : prefix + getText(); if(elementType == CSharpTokens.STRING_LITERAL) { return StringUtil.unquoteString(text); } else if(elementType == CSharpTokens.VERBATIM_STRING_LITERAL) { return getText(); //TODO [VISTALL] unquote @ "" and escape \n \t } else if(elementType == CSharpTokens.CHARACTER_LITERAL) { return StringUtil.unquoteString(text).charAt(0); } else if(elementType == CSharpTokens.UINTEGER_LITERAL) { text = text.substring(0, text.length() - 1); //cut U return getBigInteger(text); } else if(elementType == CSharpTokens.ULONG_LITERAL) { text = text.substring(0, text.length() - 2); //cut UL return getBigInteger(text); } else if(elementType == CSharpTokens.INTEGER_LITERAL) { return getBigInteger(text); } else if(elementType == CSharpTokens.LONG_LITERAL) { text = text.substring(0, text.length() - 1); //cut L return getBigInteger(text); } else if(elementType == CSharpTokens.FLOAT_LITERAL) { return Double.parseDouble(text); } else if(elementType == CSharpTokens.DOUBLE_LITERAL) { return Double.parseDouble(text); } else if(elementType == CSharpTokens.NULL_LITERAL) { return null; } else if(elementType == CSharpTokens.TRUE_KEYWORD || elementType == CSharpTokens.FALSE_KEYWORD) { return Boolean.parseBoolean(text); } throw new IllegalArgumentException(elementType.toString()); } private static BigInteger getBigInteger(String text) { int radix = 10; if(text.startsWith("0x") || text.startsWith("0X")) { radix = 16; text = text.substring(2, text.length()); } return new BigInteger(text, radix); } @Nullable @Override @RequiredReadAction public Object getValue() { return getValue(""); } @NotNull @Override @RequiredReadAction public IElementType getLiteralType() { PsiElement byType = getFirstChild(); assert byType != null; return byType.getNode().getElementType(); } @Override @RequiredReadAction public boolean isValidHost() { IElementType elementType = getLiteralType(); return elementType != CSharpTokens.CHARACTER_LITERAL && CSharpTokenSets.STRINGS.contains(elementType); } @NotNull @Override @RequiredReadAction public PsiReference[] getReferences() { return PsiReferenceService.getService().getContributedReferences(this); } @Override @RequiredReadAction public PsiLanguageInjectionHost updateText(@NotNull String s) { LeafPsiElement first = (LeafPsiElement) getFirstChild(); first.replaceWithText(s); return this; } @NotNull @Override @RequiredReadAction public LiteralTextEscaper<? extends PsiLanguageInjectionHost> createLiteralTextEscaper() { IElementType elementType = getLiteralType(); if(elementType == CSharpTokens.STRING_LITERAL) { return new CSharpStringLiteralEscaper<>(this); } else if(elementType == CSharpTokens.VERBATIM_STRING_LITERAL) { return LiteralTextEscaper.createSimple(this); } throw new IllegalArgumentException("Unknown " + elementType); } @RequiredReadAction @NotNull public static TextRange getStringValueTextRange(@NotNull CSharpConstantExpressionImpl expression) { IElementType literalType = expression.getLiteralType(); if(literalType == CSharpTokens.VERBATIM_STRING_LITERAL || literalType == CSharpTokenSets.INTERPOLATION_STRING_LITERAL) { return new TextRange(2, expression.getTextLength() - 1); } else if(literalType == CSharpTokens.STRING_LITERAL) { return new TextRange(1, expression.getTextLength() - 1); } return new TextRange(0, expression.getTextLength()); } }