Skip to content

Commit

Permalink
New minor release
Browse files Browse the repository at this point in the history
- Fixed a number of jsdoc comments.
- Changed copyrights to refer to the license file without a copyright year.
- Renamed a few interfaces to follow the interface naming rules (a leading I).
- Merged PR #81 from Aaron Braunstein.
- Fixed a number of formatting issues.
- Upgraded all dependencies to their latest version.
  • Loading branch information
mike-lischke committed Aug 8, 2023
1 parent aa6da1c commit e859609
Show file tree
Hide file tree
Showing 27 changed files with 1,217 additions and 1,027 deletions.
8 changes: 5 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,14 @@
"@typescript-eslint/restrict-plus-operands": "off",
"jsdoc/check-alignment": "error",
"jsdoc/check-indentation": "off",
"jsdoc/newline-after-description": "error",
"jsdoc/require-param-type": "off",
"jsdoc/require-returns-type": "off",
"jsdoc/tag-lines": [
// Have to switch this off, as it is not good enough to be used.
"off"
"error",
"any",
{
"startLines": 1
}
]
}
}
2 changes: 1 addition & 1 deletion LICENSE → License.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2016, 2017, Mike Lischke
Copyright (c) 2016 - present Mike Lischke

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1,862 changes: 1,035 additions & 827 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "antlr4-c3",
"version": "3.0.1",
"version": "3.1.0",
"description": "A code completion core implementation for ANTLR4 based parsers",
"author": "Mike Lischke",
"license": "MIT",
Expand Down Expand Up @@ -30,19 +30,19 @@
"antlr4ts": "0.5.0-alpha.4"
},
"devDependencies": {
"@types/jest": "29.5.0",
"@types/node": "18.15.0",
"@types/jest": "29.5.3",
"@types/node": "20.4.8",
"@types/unicode-properties": "1.3.0",
"@typescript-eslint/eslint-plugin": "5.56.0",
"@typescript-eslint/parser": "5.56.0",
"@typescript-eslint/eslint-plugin": "6.3.0",
"@typescript-eslint/parser": "6.3.0",
"antlr4ts-cli": "0.5.0-alpha.4",
"eslint": "8.36.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-jsdoc": "40.0.1",
"eslint": "8.46.0",
"eslint-plugin-import": "2.28.0",
"eslint-plugin-jsdoc": "46.4.6",
"eslint-plugin-prefer-arrow": "1.2.3",
"jest": "29.5.0",
"ts-jest": "29.0.5",
"jest": "29.6.2",
"ts-jest": "29.1.1",
"ts-node": "10.9.1",
"typescript": "5.0.2"
"typescript": "5.1.6"
}
}
16 changes: 7 additions & 9 deletions src/ArrayType.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2023, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { Type, ReferenceKind, TypeKind } from "./types";
import { IType, ReferenceKind, TypeKind } from "./types";

import { BaseSymbol } from "./BaseSymbol";

export class ArrayType extends BaseSymbol implements Type {
export class ArrayType extends BaseSymbol implements IType {

public readonly elementType: Type;
public readonly elementType: IType;
public readonly size: number; // > 0 if fixed length.

private referenceKind: ReferenceKind;

public constructor(name: string, referenceKind: ReferenceKind, elemType: Type, size = 0) {
public constructor(name: string, referenceKind: ReferenceKind, elemType: IType, size = 0) {
super(name);
this.referenceKind = referenceKind;
this.elementType = elemType;
this.size = size;
}

public get baseTypes(): Type[] { return []; }
public get baseTypes(): IType[] { return []; }
public get kind(): TypeKind { return TypeKind.Array; }
public get reference(): ReferenceKind { return this.referenceKind; }
}
6 changes: 2 additions & 4 deletions src/BaseSymbol.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2023, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { ParseTree } from "antlr4ts/tree/ParseTree";
Expand Down
6 changes: 2 additions & 4 deletions src/BlockSymbol.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2023, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { ScopedSymbol } from "./ScopedSymbol";
Expand Down
12 changes: 5 additions & 7 deletions src/ClassSymbol.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2023, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { Type, ReferenceKind, TypeKind } from "./types";
import { IType, ReferenceKind, TypeKind } from "./types";

import { FieldSymbol } from "./FieldSymbol";
import { InterfaceSymbol } from "./InterfaceSymbol";
import { MethodSymbol } from "./MethodSymbol";
import { ScopedSymbol } from "./ScopedSymbol";

/** Classes and structs. */
export class ClassSymbol extends ScopedSymbol implements Type {
export class ClassSymbol extends ScopedSymbol implements IType {
public isStruct = false;
public reference = ReferenceKind.Irrelevant;

Expand All @@ -31,7 +29,7 @@ export class ClassSymbol extends ScopedSymbol implements Type {
this.implements = impl;
}

public get baseTypes(): Type[] { return this.extends; }
public get baseTypes(): IType[] { return this.extends; }
public get kind(): TypeKind { return TypeKind.Class; }

/**
Expand Down
110 changes: 62 additions & 48 deletions src/CodeCompletionCore.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2016, 2021, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

/* eslint-disable max-classes-per-file */

import { Parser, Vocabulary, Token, TokenStream, ParserRuleContext } from "antlr4ts";
import {
ATN, ATNState, ATNStateType, Transition, TransitionType, PredicateTransition, RuleTransition, RuleStartState,
PrecedencePredicateTransition,
ATN, ATNState, ATNStateType, Transition, PredicateTransition, RuleTransition, RuleStartState,
PrecedencePredicateTransition, TransitionType,
} from "antlr4ts/atn";
import { IntervalSet } from "antlr4ts/misc/IntervalSet";

Expand All @@ -19,43 +17,49 @@ import { longestCommonPrefix } from "./utils";
export type TokenList = number[];
export type RuleList = number[];

export interface CandidateRule {
export interface ICandidateRule {
startTokenIndex: number;
ruleList: RuleList;
}

export interface RuleWithStartToken {
export interface IRuleWithStartToken {
startTokenIndex: number;
ruleIndex: number;
}

export type RuleWithStartTokenList = RuleWithStartToken[];
export type RuleWithStartTokenList = IRuleWithStartToken[];

// All the candidates which have been found. Tokens and rules are separated.
// Token entries include a list of tokens that directly follow them (see also the "following" member in the
// FollowSetWithPath class).
// Rule entries include the index of the starting token within the evaluated rule, along with a call stack of rules
// found during evaluation.
/**
* All the candidates which have been found. Tokens and rules are separated.
* Token entries include a list of tokens that directly follow them (see also the "following" member in the
* FollowSetWithPath class).
* Rule entries include the index of the starting token within the evaluated rule, along with a call stack of rules
* found during evaluation.
*/
export class CandidatesCollection {
public tokens: Map<number, TokenList> = new Map();
public rules: Map<number, CandidateRule> = new Map();
public rules: Map<number, ICandidateRule> = new Map();
}

// A record for a follow set along with the path at which this set was found.
// If there is only a single symbol in the interval set then we also collect and store tokens which follow
// this symbol directly in its rule (i.e. there is no intermediate rule transition). Only single label transitions
// are considered. This is useful if you have a chain of tokens which can be suggested as a whole, because there is
// a fixed sequence in the grammar.
/**
* A record for a follow set along with the path at which this set was found.
* If there is only a single symbol in the interval set then we also collect and store tokens which follow
* this symbol directly in its rule (i.e. there is no intermediate rule transition). Only single label transitions
* are considered. This is useful if you have a chain of tokens which can be suggested as a whole, because there is
* a fixed sequence in the grammar.
*/
class FollowSetWithPath {
public intervals: IntervalSet;
public path: RuleList = [];
public following: TokenList = [];
}

// A list of follow sets (for a given state number) + all of them combined for quick hit tests + whether they are
// exhaustive (false if subsequent yet-unprocessed rules could add further tokens to the follow set, true otherwise).
// This data is static in nature (because the used ATN states are part of a static struct: the ATN).
// Hence it can be shared between all C3 instances, however it depends on the actual parser class (type).
/**
* A list of follow sets (for a given state number) + all of them combined for quick hit tests + whether they are
* exhaustive (false if subsequent yet-unprocessed rules could add further tokens to the follow set, true otherwise).
* This data is static in nature (because the used ATN states are part of a static struct: the ATN).
* Hence it can be shared between all C3 instances, however it depends on the actual parser class (type).
*/
class FollowSetsHolder {
public sets: FollowSetWithPath[];
public combined: IntervalSet;
Expand All @@ -64,15 +68,15 @@ class FollowSetsHolder {

type FollowSetsPerState = Map<number, FollowSetsHolder>;

// Token stream position info after a rule was processed.
/** Token stream position info after a rule was processed. */
type RuleEndStatus = Set<number>;

interface IPipelineEntry {
state: ATNState;
tokenListIndex: number;
}

// The main class for doing the collection process.
/** The main class for doing the collection process. */
export class CodeCompletionCore {
private static followSetsByATN = new Map<string, FollowSetsPerState>();

Expand All @@ -94,28 +98,34 @@ export class CodeCompletionCore {

// Debugging options. Print human readable ATN state and other info.

// Not dependent on showDebugOutput. Prints the collected rules + tokens to terminal.
/** Not dependent on showDebugOutput. Prints the collected rules + tokens to terminal. */
public showResult = false;

// Enables printing ATN state info to terminal.
/** Enables printing ATN state info to terminal. */
public showDebugOutput = false;

// Only relevant when showDebugOutput is true. Enables transition printing for a state.
/** Only relevant when showDebugOutput is true. Enables transition printing for a state. */
public debugOutputWithTransitions = false;

// Also depends on showDebugOutput. Enables call stack printing for each rule recursion.
/** Also depends on showDebugOutput. Enables call stack printing for each rule recursion. */
public showRuleStack = false;

// Tailoring of the result:
// Tokens which should not appear in the candidates set.
/**
* Tailoring of the result:
* Tokens which should not appear in the candidates set.
*/
public ignoredTokens: Set<number>;

// Rules which replace any candidate token they contain.
// This allows to return descriptive rules (e.g. className, instead of ID/identifier).
/**
* Rules which replace any candidate token they contain.
* This allows to return descriptive rules (e.g. className, instead of ID/identifier).
*/
public preferredRules: Set<number>;

// Specify if preferred rules should translated top-down (higher index rule returns first) or
// bottom-up (lower index rule returns first).
/**
* Specify if preferred rules should translated top-down (higher index rule returns first) or
* bottom-up (lower index rule returns first).
*/
public translateRulesTopDown = false;

private parser: Parser;
Expand All @@ -128,11 +138,13 @@ export class CodeCompletionCore {
private tokenStartIndex = 0;
private statesProcessed = 0;

// A mapping of rule index + token stream position to end token positions.
// A rule which has been visited before with the same input position will always produce the same output positions.
/**
* A mapping of rule index + token stream position to end token positions.
* A rule which has been visited before with the same input position will always produce the same output positions.
*/
private shortcutMap: Map<number, Map<number, RuleEndStatus>> = new Map();

// The collected candidates (rules and tokens).
/** The collected candidates (rules and tokens). */
private candidates: CandidatesCollection = new CandidatesCollection();

public constructor(parser: Parser) {
Expand Down Expand Up @@ -275,15 +287,15 @@ export class CodeCompletionCore {
if (this.preferredRules.has(ruleIndex)) {
// Add the rule to our candidates list along with the current rule path,
// but only if there isn't already an entry like that.
const path = ruleWithStartTokenList.slice(0, i).map(({ ruleIndex: candidate }) => candidate);
const path = ruleWithStartTokenList.slice(0, i).map(({ ruleIndex: candidate }) => { return candidate; });
let addNew = true;
for (const rule of this.candidates.rules) {
if (rule[0] !== ruleIndex || rule[1].ruleList.length !== path.length) {
continue;
}

// Found an entry for this rule. Same path? If so don't add a new (duplicate) entry.
if (path.every((v, j) => v === rule[1].ruleList[j])) {
if (path.every((v, j) => { return v === rule[1].ruleList[j]; })) {
addNew = false;
break;
}
Expand Down Expand Up @@ -359,7 +371,7 @@ export class CodeCompletionCore {
combined.addAll(set.intervals);
}

return {sets, isExhaustive, combined};
return { sets, isExhaustive, combined };
}

/**
Expand All @@ -377,7 +389,7 @@ export class CodeCompletionCore {
private collectFollowSets(s: ATNState, stopState: ATNState, followSets: FollowSetWithPath[], stateStack: ATNState[],
ruleStack: number[]): boolean {

if (stateStack.find((x) => x === s)) {
if (stateStack.find((x) => { return x === s; })) {
return true;
}
stateStack.push(s);
Expand Down Expand Up @@ -516,11 +528,13 @@ export class CodeCompletionCore {
for (const set of followSets.sets) {
const fullPath = callStack.slice();

// Rules derived from our followSet will always start at the same token as our current rule
const followSetPath = set.path.map((path) => ({
startTokenIndex,
ruleIndex: path,
}));
// Rules derived from our followSet will always start at the same token as our current rule.
const followSetPath = set.path.map((path) => {
return {
startTokenIndex,
ruleIndex: path,
};
});

fullPath.push(...followSetPath);
if (!this.translateStackToRuleIndex(fullPath)) {
Expand Down
6 changes: 2 additions & 4 deletions src/DuplicateSymbolError.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/*
* This file is released under the MIT license.
* Copyright (c) 2023, Mike Lischke
*
* See LICENSE file for more info.
* Copyright (c) Mike Lischke. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

export class DuplicateSymbolError extends Error { }
Loading

0 comments on commit e859609

Please sign in to comment.