Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions server/src/code/highlight.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide

export enum HighlightToken {
export enum HighlightForToken {
Invalid,
Namespace, // For identifiers that declare or reference a namespace, module, or package.
Class, // For identifiers that declare or reference a class type.
Expand All @@ -25,11 +25,12 @@ export enum HighlightToken {
Number, // For tokens that represent a number literal.
Regexp, // For tokens that represent a regular expression literal.
Operator, // For tokens that represent an operator.
Builtin,
Directive,
// The following are specific to AngelScript Language Server:
Builtin, // For tokens that represent a built-in type or function.
Directive, // For tokens that represent a preprocessor directive.
}

export const highlightTokens = [
export const highlightForTokenList = [
'',
'namespace',
'class',
Expand Down Expand Up @@ -58,7 +59,7 @@ export const highlightTokens = [
'directive',
];

export enum HighlightModifier {
export enum HighlightForModifier {
Declaration, // For declarations of symbols.
Definition, // For definitions of symbols, for example, in header files.
Readonly, // For readonly variables and member fields (constants).
Expand All @@ -72,7 +73,7 @@ export enum HighlightModifier {
Nothing,
}

export const highlightModifiers = [
export const highlightForModifierList = [
'declaration',
'definition',
'readonly',
Expand Down
61 changes: 30 additions & 31 deletions server/src/compiler_analyzer/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ import {
NodeType,
NodeVar,
NodeVarAccess,
NodeWhile,
ParsedRange
NodeWhile
} from "../compiler_parser/nodes";
import {
getSourceNodeName,
Expand All @@ -58,11 +57,6 @@ import {
} from "./symbolScope";
import {checkFunctionMatch} from "./checkFunction";
import {canTypeConvert, checkTypeMatch, isAllowedToAccessMember} from "./checkType";
import {
getLocationBetween,
getNextTokenIfExist,
getNodeLocation
} from "../compiler_parser/nodesUtils";
import {
builtinBoolType,
resolvedBuiltinBool,
Expand All @@ -88,6 +82,7 @@ import assert = require("node:assert");
import {ResolvedType} from "./resolvedType";
import {analyzerDiagnostic} from "./analyzerDiagnostic";
import {TextLocation} from "../compiler_tokenizer/textLocation";
import {getBoundingLocationBetween, TokenRange} from "../compiler_parser/tokenRange";

export type HoistQueue = (() => void)[];

Expand Down Expand Up @@ -294,7 +289,7 @@ function analyzeTemplateTypes(scope: SymbolScope, nodeType: NodeType[], template
for (let i = 0; i < nodeType.length; i++) {
if (i >= templateTypes.length) {
analyzerDiagnostic.add(
getNodeLocation(nodeType[nodeType.length - 1].nodeRange),
(nodeType[nodeType.length - 1].nodeRange.getBoundingLocation()),
`Too many template types.`);
break;
}
Expand Down Expand Up @@ -349,7 +344,7 @@ function analyzeScope(parentScope: SymbolScope, nodeScope: NodeScope): SymbolSco

// Append a hint for completion of the namespace to the scope.
const complementRange: TextLocation = nextScope.location.withEnd(
getNextTokenIfExist(getNextTokenIfExist(nextScope)).location.start);
nextScope.getNextOrSelf().getNextOrSelf().location.start);
parentScope.completionHints.push({
complementKind: ComplementKind.Namespace,
complementLocation: complementRange,
Expand Down Expand Up @@ -472,7 +467,7 @@ function analyzeExprStat(scope: SymbolScope, exprStat: NodeExprStat) {
if (exprStat.assign === undefined) return;
const assign = analyzeAssign(scope, exprStat.assign);
if (assign?.isHandler !== true && assign?.symbolType instanceof SymbolFunction) {
analyzerDiagnostic.add(getNodeLocation(exprStat.assign.nodeRange), `Function call without handler.`);
analyzerDiagnostic.add(exprStat.assign.nodeRange.getBoundingLocation(), `Function call without handler.`);
}
}

Expand Down Expand Up @@ -504,7 +499,7 @@ function analyzeReturn(scope: SymbolScope, nodeReturn: NodeReturn) {
const expectedReturn = functionReturn.returnType?.symbolType;
if (expectedReturn instanceof SymbolType && expectedReturn?.identifierText === 'void') {
if (nodeReturn.assign === undefined) return;
analyzerDiagnostic.add(getNodeLocation(nodeReturn.nodeRange), `Function does not return a value.`);
analyzerDiagnostic.add(nodeReturn.nodeRange.getBoundingLocation(), `Function does not return a value.`);
} else {
checkTypeMatch(returnType, functionReturn.returnType, nodeReturn.nodeRange);
}
Expand All @@ -513,7 +508,9 @@ function analyzeReturn(scope: SymbolScope, nodeReturn: NodeReturn) {
const isGetter = key.startsWith('get_');
if (isGetter === false) {
if (nodeReturn.assign === undefined) return;
analyzerDiagnostic.add(getNodeLocation(nodeReturn.nodeRange), `Property setter does not return a value.`);
analyzerDiagnostic.add(
nodeReturn.nodeRange.getBoundingLocation(),
`Property setter does not return a value.`);
return;
}

Expand All @@ -538,7 +535,7 @@ function analyzeExpr(scope: SymbolScope, expr: NodeExpr): ResolvedType | undefin
// Evaluate by Shunting Yard Algorithm
// https://qiita.com/phenan/items/df157fef2fea590e3fa9

type Term = [ResolvedType | undefined, ParsedRange];
type Term = [ResolvedType | undefined, TokenRange];
type Op = TokenObject;

function isOp(termOrOp: (Term | Op)): termOrOp is Op {
Expand Down Expand Up @@ -580,7 +577,7 @@ function analyzeExpr(scope: SymbolScope, expr: NodeExpr): ResolvedType | undefin
if (lhs === undefined || rhs === undefined) return undefined;

outputTerm.push([analyzeExprOp(
scope, item, lhs[0], rhs[0], lhs[1], rhs[1]), {start: lhs[1].start, end: rhs[1].end}]);
scope, item, lhs[0], rhs[0], lhs[1], rhs[1]), new TokenRange(lhs[1].start, rhs[1].end)]);
} else {
outputTerm.push(item);
}
Expand Down Expand Up @@ -742,7 +739,7 @@ function analyzeBuiltinConstructorCaller(
// EXPRPREOP ::= '-' | '+' | '!' | '++' | '--' | '~' | '@'

// EXPRPOSTOP ::= ('.' (FUNCCALL | IDENTIFIER)) | ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']') | ARGLIST | '++' | '--'
function analyzeExprPostOp(scope: SymbolScope, exprPostOp: NodeExprPostOp, exprValue: ResolvedType, exprRange: ParsedRange) {
function analyzeExprPostOp(scope: SymbolScope, exprPostOp: NodeExprPostOp, exprValue: ResolvedType, exprRange: TokenRange) {
if (exprPostOp.postOp === 1) {
return analyzeExprPostOp1(scope, exprPostOp, exprValue);
} else if (exprPostOp.postOp === 2) {
Expand All @@ -753,14 +750,14 @@ function analyzeExprPostOp(scope: SymbolScope, exprPostOp: NodeExprPostOp, exprV
// ('.' (FUNCCALL | IDENTIFIER))
function analyzeExprPostOp1(scope: SymbolScope, exprPostOp: NodeExprPostOp1, exprValue: ResolvedType) {
if (exprValue.symbolType instanceof SymbolType === false) {
analyzerDiagnostic.add(getNodeLocation(exprPostOp.nodeRange), `Invalid access to type.`);
analyzerDiagnostic.add(exprPostOp.nodeRange.getBoundingLocation(), `Invalid access to type.`);
return undefined;
}

// Append a hint for complement of class members.
const complementRange = getLocationBetween(
const complementRange = getBoundingLocationBetween(
exprPostOp.nodeRange.start,
getNextTokenIfExist(exprPostOp.nodeRange.start));
exprPostOp.nodeRange.start.getNextOrSelf());
scope.completionHints.push({
complementKind: ComplementKind.Type,
complementLocation: complementRange,
Expand Down Expand Up @@ -802,7 +799,7 @@ function analyzeExprPostOp1(scope: SymbolScope, exprPostOp: NodeExprPostOp1, exp
}

// ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']')
function analyzeExprPostOp2(scope: SymbolScope, exprPostOp: NodeExprPostOp2, exprValue: ResolvedType, exprRange: ParsedRange) {
function analyzeExprPostOp2(scope: SymbolScope, exprPostOp: NodeExprPostOp2, exprValue: ResolvedType, exprRange: TokenRange) {
const args = exprPostOp.indexerList.map(indexer => analyzeAssign(scope, indexer.assign));
return analyzeOperatorAlias(
scope,
Expand Down Expand Up @@ -850,7 +847,7 @@ function analyzeLambda(scope: SymbolScope, lambda: NodeLambda): ResolvedType | u
function analyzeLiteral(scope: SymbolScope, literal: NodeLiteral): ResolvedType | undefined {
const literalValue = literal.value;
if (literalValue.isNumberToken()) {
switch (literalValue.numeric) {
switch (literalValue.numberLiteral) {
case NumberLiterals.Integer:
return resolvedBuiltinInt;
case NumberLiterals.Float:
Expand Down Expand Up @@ -955,9 +952,9 @@ function analyzeFunctionCaller(
}

// Append a hint for completion of function arguments to the scope.
const complementRange = getLocationBetween(
const complementRange = getBoundingLocationBetween(
callerArgList.nodeRange.start,
getNextTokenIfExist(callerArgList.nodeRange.end));
callerArgList.nodeRange.end.getNextOrSelf());
scope.completionHints.push({
complementKind: ComplementKind.Arguments,
complementLocation: complementRange,
Expand Down Expand Up @@ -1076,7 +1073,9 @@ export function analyzeCondition(scope: SymbolScope, condition: NodeCondition):
if (canTypeConvert(falseAssign, trueAssign)) return trueAssign;

analyzerDiagnostic.add(
getLocationBetween(condition.ternary.trueAssign.nodeRange.start, condition.ternary.falseAssign.nodeRange.end),
getBoundingLocationBetween(
condition.ternary.trueAssign.nodeRange.start,
condition.ternary.falseAssign.nodeRange.end),
`Type mismatches between '${stringifyResolvedType(trueAssign)}' and '${stringifyResolvedType(falseAssign)}'.`);
return undefined;
}
Expand All @@ -1085,7 +1084,7 @@ export function analyzeCondition(scope: SymbolScope, condition: NodeCondition):
function analyzeExprOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType | undefined, rhs: ResolvedType | undefined,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
if (operator.isReservedToken() === false) return undefined;
if (lhs === undefined || rhs === undefined) return undefined;
Expand All @@ -1105,7 +1104,7 @@ function analyzeExprOp(
function analyzeOperatorAlias(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType, rhs: ResolvedType | (ResolvedType | undefined)[],
leftRange: ParsedRange, rightRange: ParsedRange,
leftRange: TokenRange, rightRange: TokenRange,
alias: string
) {
const rhsArgs = Array.isArray(rhs) ? rhs : [rhs];
Expand Down Expand Up @@ -1140,7 +1139,7 @@ function analyzeOperatorAlias(
return checkFunctionMatch({
scope: scope,
callerIdentifier: operator,
callerRange: {start: operator, end: operator},
callerRange: new TokenRange(operator, operator),
callerArgRanges: [rightRange],
callerArgTypes: rhsArgs,
calleeFunc: aliasFunction,
Expand All @@ -1152,7 +1151,7 @@ function analyzeOperatorAlias(
function analyzeBitOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType, rhs: ResolvedType,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
if (lhs.symbolType instanceof SymbolType && rhs.symbolType instanceof SymbolType) {
if (canTypeConvert(lhs, resolvedBuiltinInt) && canTypeConvert(
Expand Down Expand Up @@ -1182,7 +1181,7 @@ const bitOpAliases = new Map<string, [string, string]>([
function analyzeMathOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType, rhs: ResolvedType,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
if (lhs.symbolType instanceof SymbolType && rhs.symbolType instanceof SymbolType) {
if (canTypeConvert(lhs, resolvedBuiltinInt) && canTypeConvert(
Expand Down Expand Up @@ -1212,7 +1211,7 @@ const mathOpAliases = new Map<string, [string, string]>([
function analyzeCompOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType, rhs: ResolvedType,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
if (lhs.symbolType instanceof SymbolType && rhs.symbolType instanceof SymbolType) {
if (canTypeConvert(lhs, rhs) || canTypeConvert(rhs, lhs)) {
Expand Down Expand Up @@ -1240,7 +1239,7 @@ const compOpAliases = new Map<string, string>([
function analyzeLogicOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType, rhs: ResolvedType,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
checkTypeMatch(lhs, new ResolvedType(builtinBoolType), leftRange);
checkTypeMatch(rhs, new ResolvedType(builtinBoolType), rightRange);
Expand All @@ -1251,7 +1250,7 @@ function analyzeLogicOp(
function analyzeAssignOp(
scope: SymbolScope, operator: TokenObject,
lhs: ResolvedType | undefined, rhs: ResolvedType | undefined,
leftRange: ParsedRange, rightRange: ParsedRange
leftRange: TokenRange, rightRange: TokenRange
): ResolvedType | undefined {
if (lhs === undefined || rhs === undefined) return undefined;
if (lhs.symbolType instanceof SymbolType && rhs.symbolType instanceof SymbolType) {
Expand Down
19 changes: 9 additions & 10 deletions server/src/compiler_analyzer/checkFunction.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import {diagnostic} from "../code/diagnostic";
import {ParsedRange} from "../compiler_parser/nodes";
import {
SymbolFunction,
} from "./symbolObject";
import {canTypeConvert} from "./checkType";
import {getNodeLocation, stringifyNodeType} from "../compiler_parser/nodesUtils";
import {stringifyNodeType} from "../compiler_parser/nodesUtils";
import {resolveTemplateTypes, stringifyResolvedType, stringifyResolvedTypes, TemplateTranslation} from "./symbolUtils";
import {SymbolScope} from "./symbolScope";
import {ResolvedType} from "./resolvedType";
import {analyzerDiagnostic} from "./analyzerDiagnostic";
import {TokenObject} from "../compiler_tokenizer/tokenObject";
import {TokenRange} from "../compiler_parser/tokenRange";

export interface FunctionMatchingArgs {
scope: SymbolScope;
callerIdentifier: TokenObject;
callerRange: ParsedRange;
callerArgRanges: ParsedRange[];
callerRange: TokenRange;
callerArgRanges: TokenRange[];
callerArgTypes: (ResolvedType | undefined)[];
calleeFunc: SymbolFunction;
templateTranslators: (TemplateTranslation | undefined)[];
Expand Down Expand Up @@ -70,7 +69,7 @@ function checkFunctionMatchInternal(
overloadedHead,
templateTranslators) === false) {
analyzerDiagnostic.add(
getNodeLocation(callerRange),
callerRange.getBoundingLocation(),
`Missing argument for parameter '${stringifyNodeType(param.type)}'.`);
}

Expand All @@ -96,7 +95,7 @@ function checkFunctionMatchInternal(
overloadedHead,
templateTranslators) === false) {
analyzerDiagnostic.add(
getNodeLocation(callerRange),
callerRange.getBoundingLocation(),
`Cannot convert '${stringifyResolvedType(actualType)}' to parameter type '${stringifyResolvedType(
expectedType)}'.`);
}
Expand All @@ -120,15 +119,15 @@ function handleTooMuchCallerArgs(args: FunctionMatchingArgs, overloadedHead: Sym
overloadedHead,
templateTranslators) === false) {
analyzerDiagnostic.add(
getNodeLocation(callerRange),
callerRange.getBoundingLocation(),
`Function has ${calleeFunc.sourceNode.paramList.length} parameters, but ${callerArgTypes.length} were provided.`);
}

return calleeFunc.returnType;
}

function handleErrorWhenOverloaded(
callerRange: ParsedRange,
callerRange: TokenRange,
callerArgs: (ResolvedType | undefined)[],
calleeFunc: SymbolFunction,
overloadedHead: SymbolFunction,
Expand All @@ -147,6 +146,6 @@ function handleErrorWhenOverloaded(
cursor = cursor.nextOverload;
}

analyzerDiagnostic.add(getNodeLocation(callerRange), message);
analyzerDiagnostic.add(callerRange.getBoundingLocation(), message);
return true;
}
11 changes: 5 additions & 6 deletions server/src/compiler_analyzer/checkType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import {
SymbolObject,
SymbolType, isSourceNodeClassOrInterface,
} from "./symbolObject";
import {AccessModifier, NodeName, ParsedRange} from "../compiler_parser/nodes";
import {getNodeLocation} from "../compiler_parser/nodesUtils";
import {AccessModifier, NodeName} from "../compiler_parser/nodes";
import {findScopeShallowly, findScopeWithParentByNodes, isScopeChildOrGrandchild, SymbolScope} from "./symbolScope";
import assert = require("assert");
import {findSymbolShallowly, resolveTemplateType, stringifyResolvedType} from "./symbolUtils";
import {ResolvedType} from "./resolvedType";
import {isSameToken} from "../compiler_tokenizer/tokenUtils";
import {analyzerDiagnostic} from "./analyzerDiagnostic";
import {TokenRange} from "../compiler_parser/tokenRange";

/**
* Check if the source type can be converted to the destination type.
Expand All @@ -23,12 +22,12 @@ import {analyzerDiagnostic} from "./analyzerDiagnostic";
export function checkTypeMatch(
src: ResolvedType | undefined,
dest: ResolvedType | undefined,
nodeRange: ParsedRange,
nodeRange: TokenRange,
): boolean {
if (canTypeConvert(src, dest)) return true;

analyzerDiagnostic.add(
getNodeLocation(nodeRange),
nodeRange.getBoundingLocation(),
`'${stringifyResolvedType(src)}' cannot be converted to '${stringifyResolvedType(dest)}'.`);
return false;
}
Expand Down Expand Up @@ -151,7 +150,7 @@ function canCastFromPrimitiveType(
const destNode = destType.sourceNode;

if (srcType.isTypeParameter) {
return destType.isTypeParameter && isSameToken(srcType.declaredPlace, destType.declaredPlace);
return destType.isTypeParameter && srcType.declaredPlace.equals(destType.declaredPlace);
}

if (srcType.identifierText === 'void') {
Expand Down
Loading