From c3d5d3541b5d1064b5a82c38765d4d3a14a43bcd Mon Sep 17 00:00:00 2001 From: Pier Paolo MAMMI Date: Mon, 17 Aug 2026 18:22:58 +0200 Subject: [PATCH] refine blocks detection --- src/parser.ts | 9 ++ src/tokenizer.ts | 10 +- syntaxes/eftl.tmLanguage.json | 267 ++++++++++++++++------------------ 3 files changed, 133 insertions(+), 153 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index c1743a8..d211bd2 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -233,6 +233,9 @@ export class EftlParser { case TokenType.VALUE_OF: case TokenType.SIZE_OF: case TokenType.HEADER: + if (!token.value.endsWith('/]')) { + this.pushBlock(token); + } this.advance(); break; @@ -249,6 +252,9 @@ export class EftlParser { } private pushBlock(token: Token): void { + if (token.value.endsWith('/]')) { + return; // It's self-closing, don't push to stack + } this.blockStack.push({ type: token.type, token }); } @@ -295,6 +301,9 @@ export class EftlParser { [TokenType.TRIM_OPEN]: '[/TRIM]', [TokenType.CONTAINS_OPEN]: '[/CONTAINS]', [TokenType.FORMAT_OPEN]: '[/FORMAT]', + [TokenType.VALUE_OF]: '[/VALUE_OF]', + [TokenType.SIZE_OF]: '[/SIZE_OF]', + [TokenType.HEADER]: '[/HEADER]', [TokenType.EXPR_OPEN]: '%]', [TokenType.EXPR_OUTPUT_OPEN]: '%]', [TokenType.COMMENT_OPEN]: '--]' diff --git a/src/tokenizer.ts b/src/tokenizer.ts index d472ff2..04dcbcb 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -298,7 +298,7 @@ export class EftlTokenizer { private scanVarOpen(startLine: number, startColumn: number): void { let value = '[VAR'; - // Scan until we find ] or ] + // Scan until we find ] while (this.pos < this.source.length && this.peek() !== ']') { value += this.advance(); } @@ -328,13 +328,7 @@ export class EftlTokenizer { break; } if (ch === ']') { - // Not self-closing, error - this.errors.push({ - message: `Expected self-closing tag: [${tagName} ... /]`, - line: startLine, - column: startColumn, - length: value.length - }); + // Could be block start, let parser handle it if it's supposed to be self-closing break; } } diff --git a/syntaxes/eftl.tmLanguage.json b/syntaxes/eftl.tmLanguage.json index 4c90163..52e4ad2 100644 --- a/syntaxes/eftl.tmLanguage.json +++ b/syntaxes/eftl.tmLanguage.json @@ -94,7 +94,7 @@ }, { "name": "keyword.operator.arithmetic.eftl", - "match": "[+\\-*/%]" + "match": "([+\\-*%]|/(?!\\]))" }, { "name": "keyword.operator.comparison.eftl", @@ -129,45 +129,85 @@ } ] }, - "tags": { + "attributes": { "patterns": [ { - "name": "meta.tag.data.eftl", - "begin": "(\\[TAG\\])", - "end": "(\\[/TAG\\])", - "beginCaptures": { - "1": { "name": "entity.name.tag.eftl" } - }, - "endCaptures": { - "1": { "name": "entity.name.tag.eftl" } - }, - "patterns": [ - { "include": "#tag-content" } - ] + "comment": "name attribute", + "match": "\\b(name)\\b\\s*(=)\\s*(\"(.*?)\")", + "captures": { + "1": { "name": "entity.other.attribute-name.eftl" }, + "2": { "name": "punctuation.separator.key-value.eftl" }, + "3": { "name": "string.quoted.double.eftl" }, + "4": { "name": "variable.other.eftl" } + } + }, + { + "comment": "type attribute", + "match": "\\b(type)\\b\\s*(=)\\s*(\"(string|boolean|number|date|object|iterable)\")", + "captures": { + "1": { "name": "entity.other.attribute-name.eftl" }, + "2": { "name": "punctuation.separator.key-value.eftl" }, + "3": { "name": "string.quoted.double.eftl" }, + "4": { "name": "support.type.primitive.eftl" } + } + }, + { + "comment": "generic attribute", + "match": "\\b([a-zA-Z_][a-zA-Z0-9_-]*)\\b\\s*(=)\\s*(\"(.*?)\")", + "captures": { + "1": { "name": "entity.other.attribute-name.eftl" }, + "2": { "name": "punctuation.separator.key-value.eftl" }, + "3": { "name": "string.quoted.double.eftl" } + } } ] }, - "tag-content": { + "tag-open-context": { + "patterns": [ + { "include": "#attributes" }, + { "include": "#expressions" }, + { "include": "#functions" }, + { "include": "#tags" } + ] + }, + "tags": { "patterns": [ { - "name": "support.function.builtin.eftl", - "match": "\\b(GETVALUEBYTAG|SCHEMAID|PLUGIN_DOM_PARAM)\\b" + "name": "meta.tag.block.eftl", + "begin": "(\\[)(TAG)(?:\\s+[^\\x00]*?)?(?