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]

Reply via email to