Skip to content

Commit 84d85f5

Browse files
committed
Add support for constants
1 parent 8e076f5 commit 84d85f5

File tree

13 files changed

+143
-6
lines changed

13 files changed

+143
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Support for basic spell checking and custom dictionary.
66
- Support for specific parameter types in triggers.
77
- Support for game variable type checking/refactoring/find usages.
8+
- Support for constant type checking/refactoring/find usages.
89

910
## [1.1.0] - 2023-08-11
1011

src/main/gen/io/runescript/plugin/lang/psi/RsConstantExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.jetbrains.annotations.*;
66
import com.intellij.psi.PsiElement;
77

8-
public interface RsConstantExpression extends RsExpression {
8+
public interface RsConstantExpression extends RsExpression, RsNamedElement {
99

1010
@NotNull
1111
RsNameLiteral getNameLiteral();

src/main/gen/io/runescript/plugin/lang/psi/RsVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public void visitConditionOp(@NotNull RsConditionOp o) {
6767

6868
public void visitConstantExpression(@NotNull RsConstantExpression o) {
6969
visitExpression(o);
70+
// visitNamedElement(o);
7071
}
7172

7273
public void visitCoordLiteralExpression(@NotNull RsCoordLiteralExpression o) {

src/main/gen/io/runescript/plugin/lang/psi/impl/RsConstantExpressionImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
import com.intellij.psi.PsiElementVisitor;
99
import com.intellij.psi.util.PsiTreeUtil;
1010
import static io.runescript.plugin.lang.psi.RsElementTypes.*;
11+
import io.runescript.plugin.lang.psi.mixin.RsConstantExpressionMixin;
1112
import io.runescript.plugin.lang.psi.*;
1213

13-
public class RsConstantExpressionImpl extends RsExpressionImpl implements RsConstantExpression {
14+
public class RsConstantExpressionImpl extends RsConstantExpressionMixin implements RsConstantExpression {
1415

1516
public RsConstantExpressionImpl(@NotNull ASTNode node) {
1617
super(node);
1718
}
1819

19-
@Override
2020
public void accept(@NotNull RsVisitor visitor) {
2121
visitor.visitConstantExpression(this);
2222
}

src/main/grammars/RuneScript.bnf

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,10 @@ GosubExpression ::= '~' NameLiteral ArgumentList? {
238238
implements="io.runescript.plugin.lang.psi.RsNamedElement"
239239
}
240240
ArgumentList ::= '(' ExpressionList? ')'
241-
ConstantExpression ::= '^' NameLiteral
241+
ConstantExpression ::= '^' NameLiteral {
242+
mixin="io.runescript.plugin.lang.psi.mixin.RsConstantExpressionMixin"
243+
implements="io.runescript.plugin.lang.psi.RsNamedElement"
244+
}
242245
DynamicExpression ::= NameLiteral {
243246
mixin="io.runescript.plugin.lang.psi.mixin.RsDynamicExpressionMixin"
244247
implements="io.runescript.plugin.lang.psi.RsNamedElement"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.runescript.plugin.ide.inspections
2+
3+
import com.intellij.codeInspection.LocalInspectionTool
4+
import com.intellij.codeInspection.ProblemHighlightType
5+
import com.intellij.codeInspection.ProblemsHolder
6+
import com.intellij.psi.PsiElementVisitor
7+
import io.runescript.plugin.ide.RsBundle
8+
import io.runescript.plugin.lang.psi.RsConstantExpression
9+
import io.runescript.plugin.lang.psi.RsScopedVariableExpression
10+
import io.runescript.plugin.lang.psi.RsVisitor
11+
12+
class RuneScriptUnresolvedConstantInspection : LocalInspectionTool() {
13+
14+
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
15+
return object : RsVisitor() {
16+
override fun visitConstantExpression(o: RsConstantExpression) {
17+
val reference = o.reference ?: return
18+
if (reference.resolve() == null) {
19+
holder.registerProblem(o,
20+
RsBundle.message("inspection.error.unresolved.constant", o.nameLiteral.text),
21+
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL
22+
)
23+
}
24+
}
25+
}
26+
}
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.runescript.plugin.lang.psi.mixin
2+
3+
import com.intellij.extapi.psi.ASTWrapperPsiElement
4+
import com.intellij.lang.ASTNode
5+
import com.intellij.psi.PsiElement
6+
import com.intellij.psi.PsiReference
7+
import com.intellij.refactoring.suggested.startOffset
8+
import io.runescript.plugin.lang.psi.RsConstantExpression
9+
import io.runescript.plugin.lang.psi.RsPsiImplUtil
10+
import io.runescript.plugin.lang.psi.refs.RsConstantReference
11+
12+
abstract class RsConstantExpressionMixin(node: ASTNode) : ASTWrapperPsiElement(node), RsConstantExpression {
13+
14+
override fun getReference(): PsiReference? {
15+
return RsConstantReference(this)
16+
}
17+
18+
override fun getName(): String? {
19+
return RsPsiImplUtil.getName(nameLiteral)
20+
}
21+
22+
override fun setName(name: String): PsiElement {
23+
return RsPsiImplUtil.setName(nameLiteral, name)
24+
}
25+
26+
override fun getTextOffset(): Int {
27+
return nameLiteral.startOffset
28+
}
29+
30+
override fun getNameIdentifier(): PsiElement? {
31+
return nameLiteral
32+
}
33+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.runescript.plugin.lang.psi.refs
2+
3+
import com.intellij.psi.*
4+
import io.runescript.plugin.lang.psi.RsConstantExpression
5+
import io.runescript.plugin.lang.psi.type.RsPrimitiveType
6+
import io.runescript.plugin.symbollang.psi.index.RsSymbolIndex
7+
8+
class RsConstantReference(element: RsConstantExpression) :
9+
PsiReferenceBase<RsConstantExpression>(element, element.nameLiteral.textRangeInParent), PsiPolyVariantReference {
10+
11+
override fun resolve(): PsiElement? {
12+
val result = multiResolve(false)
13+
return result.singleOrNull()?.element
14+
}
15+
16+
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
17+
val symbol = RsSymbolIndex.lookup(element.project, RsPrimitiveType.CONSTANT, element.name!!)
18+
?: return emptyArray()
19+
return arrayOf(PsiElementResolveResult(symbol))
20+
}
21+
22+
override fun handleElementRename(newElementName: String): PsiElement {
23+
element.setName(newElementName)
24+
return element
25+
}
26+
}

src/main/kotlin/io/runescript/plugin/lang/psi/type/RsPrimitiveType.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ enum class RsPrimitiveType(val literal: String, val referencable: Boolean = true
5454
HOOK("hook", referencable = false),
5555
VARPHOOK("varphook", referencable = false),
5656
STATHOOK("stathook", referencable = false),
57-
INVHOOK("invhook", referencable = false);
57+
INVHOOK("invhook", referencable = false),
58+
CONSTANT("constant", referencable = false);
5859

5960
override val representation: String
6061
get() = literal

src/main/kotlin/io/runescript/plugin/lang/psi/type/inference/RsTypeInferenceVisitor.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,41 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
485485
}
486486

487487
override fun visitConstantExpression(o: RsConstantExpression) {
488-
// TODO(Walied): Implement when constants have references
488+
val reference = o.reference?.resolve() as? RsSymSymbol
489+
val type = o.typeHint
490+
if (reference == null || type !is RsPrimitiveType || !type.referencable) {
491+
o.type = RsErrorType
492+
return
493+
}
489494
o.type = o.typeHint
495+
val value = reference.fieldList[1].text
496+
when (type) {
497+
RsPrimitiveType.STRING -> {
498+
// Do nothing
499+
}
500+
501+
RsPrimitiveType.INT -> {
502+
val radix: Int
503+
val trimmedValue: String
504+
if (value.startsWith("0x")) {
505+
radix = 16
506+
trimmedValue = value.substring(2)
507+
} else {
508+
radix = 10
509+
trimmedValue = value
510+
}
511+
if (trimmedValue.toIntOrNull(radix) == null) {
512+
o.error("Could not convert constant value '${value}' to an integer number.")
513+
}
514+
}
515+
516+
else -> {
517+
val configReference = RsSymbolIndex.lookup(o.project, type, value)
518+
if (configReference == null) {
519+
o.error("Could not resolve constant value '${value} to a reference.'")
520+
}
521+
}
522+
}
490523
}
491524

492525
override fun visitNullLiteralExpression(o: RsNullLiteralExpression) {

0 commit comments

Comments
 (0)