This is an automated email from the ASF dual-hosted git repository.
porcelli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new 59876d40716 kie-issue#1134: Autocomplete and colorize should support
local variable in iterator expressions (for, every, some) (#2296)
59876d40716 is described below
commit 59876d40716fb141a4f4446435b79e3311ad81b5
Author: Daniel José dos Santos <[email protected]>
AuthorDate: Wed May 8 19:05:57 2024 -0300
kie-issue#1134: Autocomplete and colorize should support local variable in
iterator expressions (for, every, some) (#2296)
---
.../src/parser/FeelSyntacticSymbolNature.ts | 5 ++
.../src/parser/FeelVariablesParser.ts | 3 +-
.../src/parser/VariableContext.ts | 5 ++
.../src/parser/VariablesRepository.ts | 77 ++++++++++++++++++----
.../src/parser/grammar/ParserHelper.ts | 28 ++++----
.../src/parser/grammar/Scope.ts | 6 ++
.../src/parser/grammar/ScopeImpl.ts | 19 +++++-
.../src/parser/grammar/VariableSymbol.ts | 16 ++++-
packages/feel-input-component/src/FeelConfigs.ts | 3 +-
packages/feel-input-component/src/FeelInput.tsx | 4 +-
.../feel-input-component/src/themes/Element.ts | 3 +-
11 files changed, 135 insertions(+), 34 deletions(-)
diff --git
a/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
b/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
index 8de272ed592..108b5443484 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
@@ -42,4 +42,9 @@ export enum FeelSyntacticSymbolNature {
* Parameters of functions.
*/
Parameter,
+
+ /**
+ * Variables which the parser currently doesn't know if it is valid or not
because they are validated at runtime.
+ */
+ DynamicVariable,
}
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
b/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
index 970895b4a7f..78956e65279 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
@@ -132,7 +132,8 @@ export class FeelVariablesParser {
context.variable.value,
context.variable.typeRef ? this.createType(context.variable.typeRef) :
undefined,
context.variable.feelSyntacticSymbolNature,
- context.variable
+ context.variable,
+ context.allowDynamicVariables
);
}
}
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/VariableContext.ts
b/packages/dmn-feel-antlr4-parser/src/parser/VariableContext.ts
index 2861f3feaa2..bea41c02d29 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/VariableContext.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/VariableContext.ts
@@ -54,4 +54,9 @@ export interface VariableContext {
* Input nodes that define variables.
*/
inputVariables: Array<string>;
+
+ /**
+ * Dynamic variables are variables only validated during runtime.
+ */
+ allowDynamicVariables?: boolean;
}
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
index 78988ed333d..c34686d3c64 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
@@ -122,7 +122,7 @@ export class VariablesRepository {
expressions: new Map<string, Expression>(),
};
- const newContext = {
+ const newContext: VariableContext = {
uuid: variableUuid,
parent: parentContext,
variable: newVariable,
@@ -285,14 +285,16 @@ export class VariablesRepository {
name: string,
variableType: FeelSyntacticSymbolNature,
parent?: VariableContext,
- typeRef?: string
+ typeRef?: string,
+ allowDynamicVariables?: boolean
) {
const node = this.createVariableNode(
this.buildVariableUuid(uuid),
this.buildName(name),
variableType,
parent,
- typeRef
+ typeRef,
+ allowDynamicVariables
);
this.variablesIndexedByUuid.set(this.buildVariableUuid(uuid), node);
@@ -305,13 +307,15 @@ export class VariablesRepository {
name: string,
variableType: FeelSyntacticSymbolNature,
parent: VariableContext | undefined,
- typeRef: string | undefined
- ) {
+ typeRef: string | undefined,
+ allowDynamicVariables: boolean | undefined
+ ): VariableContext {
return {
uuid: uuid,
children: new Map<string, VariableContext>(),
parent: parent,
inputVariables: new Array<string>(),
+ allowDynamicVariables: allowDynamicVariables,
variable: {
value: name,
feelSyntacticSymbolNature: variableType,
@@ -481,29 +485,76 @@ export class VariablesRepository {
}
private addIterable(parent: VariableContext, expression: DmnSome | DmnEvery)
{
- if (expression.satisfies.expression) {
- this.addInnerExpression(parent, expression.satisfies.expression);
- }
+ const localParent = this.addIteratorVariable(parent, expression);
+
if (expression.in.expression) {
- this.addInnerExpression(parent, expression.in.expression);
+ this.addInnerExpression(localParent, expression.in.expression);
+ }
+ if (expression.satisfies.expression) {
+ this.addInnerExpression(localParent, expression.satisfies.expression);
}
}
private addFor(parent: VariableContext, expression: DmnFor) {
+ const localParent = this.addIteratorVariable(parent, expression);
+
if (expression.return.expression) {
- this.addInnerExpression(parent, expression.return.expression);
+ this.addInnerExpression(localParent, expression.return.expression);
}
if (expression.in.expression) {
- this.addInnerExpression(parent, expression.in.expression);
+ this.addInnerExpression(localParent, expression.in.expression);
+ }
+ }
+
+ private addFilterVariable(parent: VariableContext, expression: DmnFilter) {
+ let type = undefined;
+
+ // We're assuming that the 'in' expression is with the correct type (a
list of @_typeRef).
+ // If it is not the expression will fail anyway.
+ if (expression.in.expression) {
+ type = expression.in.expression["@_typeRef"];
+ }
+ const localParent = this.addVariable(
+ expression["@_id"] ?? "",
+ "item",
+ FeelSyntacticSymbolNature.LocalVariable,
+ parent,
+ type,
+ true
+ );
+
+ return localParent;
+ }
+
+ private addIteratorVariable(parent: VariableContext, expression: DmnFor |
DmnEvery | DmnSome) {
+ let localParent = parent;
+ if (expression["@_iteratorVariable"]) {
+ let type = undefined;
+
+ // We're assuming that the 'in' expression is with the correct type (a
list of @_typeRef).
+ // If it is not the expression will fail anyway.
+ if (expression.in.expression) {
+ type = expression.in.expression["@_typeRef"];
+ }
+ localParent = this.addVariable(
+ expression["@_id"] ?? "",
+ expression["@_iteratorVariable"],
+ FeelSyntacticSymbolNature.LocalVariable,
+ parent,
+ type,
+ true
+ );
}
+ return localParent;
}
private addFilter(parent: VariableContext, expression: DmnFilter) {
+ const localParent = this.addFilterVariable(parent, expression);
if (expression.in.expression) {
- this.addInnerExpression(parent, expression.in.expression);
+ this.addInnerExpression(localParent, expression.in.expression);
}
if (expression.match.expression) {
- this.addInnerExpression(parent, expression.match.expression);
+ this.addInnerExpression(localParent, expression.match.expression);
}
}
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/grammar/ParserHelper.ts
b/packages/dmn-feel-antlr4-parser/src/parser/grammar/ParserHelper.ts
index 6763d4ab1ee..7c38be222dd 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/grammar/ParserHelper.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/grammar/ParserHelper.ts
@@ -57,12 +57,15 @@ export class ParserHelper {
return this._variables;
}
- public pushScope(type?: Type) {
- this.currentScope = new ScopeImpl(this.currentName.peek(),
this.currentScope, type);
+ public pushScope(type?: Type, allowDynamicVariables?: boolean) {
+ this.currentScope = new ScopeImpl(this.currentName.peek(),
this.currentScope, type, allowDynamicVariables);
}
public popScope() {
this.currentScope = this.currentScope?.getParentScope();
+ if (this.currentScope?.allowDynamicVariables) {
+ this.currentScope = this.currentScope.getParentScope();
+ }
}
public enableDynamicResolution() {
@@ -107,13 +110,15 @@ export class ParserHelper {
variable: string | ParserRuleContext,
type?: Type,
variableType?: FeelSyntacticSymbolNature,
- variableSource?: Variable
+ variableSource?: Variable,
+ allowDynamicVariables?: boolean
) {
const variableSymbol = new VariableSymbol(
variable instanceof ParserRuleContext ? this.getName(variable) :
variable,
type,
variableType,
- variableSource
+ variableSource,
+ allowDynamicVariables
);
if (variableSymbol.getId()) {
@@ -143,18 +148,9 @@ export class ParserHelper {
const s = this.currentScope?.getChildScopes().get(scopeName);
if (s != null) {
this.currentScope = s;
-
- //const type = this.currentScope.getType();
- // if (type && type === BuiltInType.UNKNOWN) {
- // this.enableDynamicResolution();
- // }
} else {
const resolved = this.currentScope?.resolve(scopeName);
const scopeType = resolved?.getType();
- // if (scopeType instanceof GenListType) {
- // scopeType = ((GenListType) scopeType).getGen();
- // }
-
if (resolved != null && scopeType instanceof MapBackedType) {
this.pushScope(scopeType);
for (const f of scopeType.properties) {
@@ -198,7 +194,6 @@ export class ParserHelper {
} else {
const symbol = this.currentScope?.resolve(variableName);
if (symbol) {
- symbol.getType();
if (symbol instanceof VariableSymbol) {
const scopeSymbols = [];
if ((symbol as VariableSymbol).getType() instanceof MapBackedType) {
@@ -210,6 +205,11 @@ export class ParserHelper {
});
}
}
+
+ if (symbol.allowDynamicVariables) {
+ this.pushScope(undefined, true);
+ }
+
this.variables.push(
new FeelVariable(
start,
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/grammar/Scope.ts
b/packages/dmn-feel-antlr4-parser/src/parser/grammar/Scope.ts
index cf71f23d028..08d6d2eb7d6 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/grammar/Scope.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/grammar/Scope.ts
@@ -84,4 +84,10 @@ export interface Scope {
getSymbols(): Map<string, Symbol>;
getType(): Type | undefined;
+
+ /**
+ * Allow the scope to accept variables that are validate during the runtime
(dynamic variables),
+ * without marking them as invalid or valid variables.
+ */
+ allowDynamicVariables: boolean | undefined;
}
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/grammar/ScopeImpl.ts
b/packages/dmn-feel-antlr4-parser/src/parser/grammar/ScopeImpl.ts
index e5ea9b35ef9..16c86905704 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/grammar/ScopeImpl.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/grammar/ScopeImpl.ts
@@ -23,6 +23,8 @@ import { Symbol } from "./Symbol";
import { TokenTree } from "./TokenTree";
import { CharStreams, Token } from "antlr4";
import FEEL_1_1Lexer from "./generated-parser/FEEL_1_1Lexer";
+import { VariableSymbol } from "./VariableSymbol";
+import { FeelSyntacticSymbolNature } from "../FeelSyntacticSymbolNature";
export class ScopeImpl implements Scope {
private readonly name?: string;
@@ -31,18 +33,24 @@ export class ScopeImpl implements Scope {
private readonly childScopes: Map<string, Scope>;
private readonly symbols: Map<string, Symbol>;
private tokenTree?: TokenTree;
+ private readonly _allowDynamicVariables?: boolean;
- public constructor(name?: string, parentScope?: Scope, type?: Type) {
+ public constructor(name?: string, parentScope?: Scope, type?: Type,
allowDynamicVariables?: boolean) {
this.childScopes = new Map<string, Scope>();
this.symbols = new Map<string, Symbol>();
this.name = name;
this.parentScope = parentScope;
this.type = type;
+ this._allowDynamicVariables = allowDynamicVariables;
if (parentScope) {
parentScope.addChildScope(this);
}
}
+ get allowDynamicVariables(): boolean | undefined {
+ return this._allowDynamicVariables;
+ }
+
addChildScope(scope: Scope): void {
this.childScopes.set(scope.getName(), scope);
}
@@ -110,6 +118,15 @@ export class ScopeImpl implements Scope {
resolve(qualifiedName: string[]): Symbol | undefined;
resolve(parameter: string | string[]): Symbol | undefined {
if (typeof parameter === "string") {
+ if (this._allowDynamicVariables) {
+ return new VariableSymbol(
+ parameter,
+ {
+ name: "name",
+ },
+ FeelSyntacticSymbolNature.DynamicVariable
+ );
+ }
return this.resolveId(parameter);
} else {
return this.resolveQualifiedName(parameter);
diff --git
a/packages/dmn-feel-antlr4-parser/src/parser/grammar/VariableSymbol.ts
b/packages/dmn-feel-antlr4-parser/src/parser/grammar/VariableSymbol.ts
index eeeab198aba..3073cefa241 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/grammar/VariableSymbol.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/grammar/VariableSymbol.ts
@@ -22,16 +22,24 @@ import { Type } from "./Type";
import { FeelSyntacticSymbolNature } from "../FeelSyntacticSymbolNature";
import { Variable } from "../Variable";
+import { Scope } from "./Scope";
export class VariableSymbol extends BaseSymbol {
private readonly _symbolType: FeelSyntacticSymbolNature | undefined;
-
private readonly _variableSource: Variable | undefined;
+ private readonly _allowDynamicVariables: boolean | undefined;
- constructor(id?: string, type?: Type, variableType?:
FeelSyntacticSymbolNature, variableSource?: Variable) {
+ constructor(
+ id?: string,
+ type?: Type,
+ variableType?: FeelSyntacticSymbolNature,
+ variableSource?: Variable,
+ allowDynamicVariables?: boolean
+ ) {
super(id, type);
this._symbolType = variableType;
this._variableSource = variableSource;
+ this._allowDynamicVariables = allowDynamicVariables;
}
get symbolType(): FeelSyntacticSymbolNature | undefined {
@@ -41,4 +49,8 @@ export class VariableSymbol extends BaseSymbol {
get variableSource(): Variable | undefined {
return this._variableSource;
}
+
+ get allowDynamicVariables(): boolean | undefined {
+ return this._allowDynamicVariables;
+ }
}
diff --git a/packages/feel-input-component/src/FeelConfigs.ts
b/packages/feel-input-component/src/FeelConfigs.ts
index 85b2d9a0374..c4b596d9bc8 100644
--- a/packages/feel-input-component/src/FeelConfigs.ts
+++ b/packages/feel-input-component/src/FeelConfigs.ts
@@ -35,10 +35,11 @@ export const feelTheme = ():
Monaco.editor.IStandaloneThemeData => {
{ token: Element[Element.FeelBoolean], foreground: "#26268D", fontStyle:
"bold" },
{ token: Element[Element.FeelString], foreground: "#067D17" },
{ token: Element[Element.FeelFunction], foreground: "#00627A" },
- { token: Element[Element.InputDataVariable], foreground: "#917632",
fontStyle: "underline" },
+ { token: Element[Element.Variable], foreground: "#917632", fontStyle:
"underline" },
{ token: Element[Element.FunctionCall], foreground: "#917632",
fontStyle: "underline italic" },
{ token: Element[Element.UnknownVariable], foreground: "#ff0000",
fontStyle: "underline bold" },
{ token: Element[Element.FunctionParameterVariable], foreground:
"#036e9b", fontStyle: "italic" },
+ { token: Element[Element.DynamicVariable], foreground: "#8b97a2",
fontStyle: "underline" },
],
colors: {
"editorLineNumber.foreground": "#000000",
diff --git a/packages/feel-input-component/src/FeelInput.tsx
b/packages/feel-input-component/src/FeelInput.tsx
index aea4fe0c949..ef75e673fec 100644
--- a/packages/feel-input-component/src/FeelInput.tsx
+++ b/packages/feel-input-component/src/FeelInput.tsx
@@ -81,7 +81,9 @@ function getTokenTypeIndex(symbolType:
FeelSyntacticSymbolNature) {
default:
case FeelSyntacticSymbolNature.LocalVariable:
case FeelSyntacticSymbolNature.GlobalVariable:
- return Element.InputDataVariable;
+ return Element.Variable;
+ case FeelSyntacticSymbolNature.DynamicVariable:
+ return Element.DynamicVariable;
case FeelSyntacticSymbolNature.Unknown:
return Element.UnknownVariable;
case FeelSyntacticSymbolNature.Invocable:
diff --git a/packages/feel-input-component/src/themes/Element.ts
b/packages/feel-input-component/src/themes/Element.ts
index 1080e01be23..1543ab821f9 100644
--- a/packages/feel-input-component/src/themes/Element.ts
+++ b/packages/feel-input-component/src/themes/Element.ts
@@ -23,8 +23,9 @@ export enum Element {
FeelBoolean,
FeelString,
FeelFunction,
- InputDataVariable,
+ Variable,
FunctionCall,
UnknownVariable,
FunctionParameterVariable,
+ DynamicVariable,
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]