From afc2d6cd213ce38ef22859e8568ee3a7f6bd37a6 Mon Sep 17 00:00:00 2001 From: George Lemon Date: Fri, 22 Mar 2024 19:55:43 +0200 Subject: [PATCH] add support for iterable ranges `for $i in 0..100` Signed-off-by: George Lemon --- src/tim/engine/compilers/html.nim | 11 +++++++- src/tim/engine/parser.nim | 42 ++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/tim/engine/compilers/html.nim b/src/tim/engine/compilers/html.nim index e84f89e..a8a5a7e 100755 --- a/src/tim/engine/compilers/html.nim +++ b/src/tim/engine/compilers/html.nim @@ -909,6 +909,15 @@ template loopEvaluator(kv, items: Node) = node.loopItem.identPairs[1].varValue = nil handleBreakCommand(x) else: discard + of ntIndexRange: + for i in items.rangeNodes[0].iVal .. items.rangeNodes[1].iVal: + newScope(scopetables) + node.loopItem.varValue = ast.newInteger(i) + c.varExpr(node.loopItem, scopetables) + let x = c.walkNodes(node.loopBody, scopetables) + clearScope(scopetables) + node.loopItem.varValue = nil + handleBreakCommand(x) else: let x = @[ntLitString, ntLitArray, ntLitObject] compileErrorWithArgs(typeMismatch, [$(items.nt), x.join(" ")]) @@ -934,7 +943,7 @@ proc evalLoop(c: var HtmlCompiler, node: Node, of ntBracketExpr: let items = c.bracketEvaluator(node.loopItems, scopetables) loopEvaluator(node.loopItem, items) - of ntLitString: + of ntLitString, ntIndexRange: loopEvaluator(node.loopItem, node.loopItems) else: compileErrorWithArgs(invalidIterator) diff --git a/src/tim/engine/parser.nim b/src/tim/engine/parser.nim index 6ba877e..c18fa10 100755 --- a/src/tim/engine/parser.nim +++ b/src/tim/engine/parser.nim @@ -18,24 +18,24 @@ type Parser* = object lvl: int # parser internals lex: Lexer - ## A pkg/toktok instance + # A pkg/toktok instance prev, curr, next: TokenTuple - ## Lexer internals + # Lexer internals engine: TimEngine - ## TimEngine instance + # TimEngine instance tpl: TimTemplate - ## A `TimTemplate` instance that represents the - ## currently parsing template + # A `TimTemplate` instance that represents the + # currently parsing template logger*: Logger ## Store warning and errors while parsing hasErrors*, nilNotError, hasLoadedView, isMain, refreshAst: bool parentNode: seq[Node] - ## Parser internals + # Parser internals includes: Table[string, Meta] - ## A table to store all `@include` statements + # A table to store all `@include` statements tree: Ast - ## The generated Abstract Syntax Tree + # The generated Abstract Syntax Tree PrefixFunction = proc(p: var Parser, excludes, includes: set[TokenKind] = {}): Node {.gcsafe.} InfixFunction = proc(p: var Parser, lhs: Node): Node {.gcsafe.} @@ -703,11 +703,24 @@ prefixHandle pFor: pairNode.identPairs[1] = vNode result.loopItem = pairNode walk p + let inx = p.curr expectWalk tkIN - expect {tkIdentVar, tkString, tkLB}: # todo function call + if p.curr in {tkIdentVar, tkString, tkLB}: + # expect {tkIdentVar, tkString, tkLB, tkInteger}: # todo function call let items = p.parsePrefix() caseNotNil items: result.loopItems = items + elif p.curr is tkInteger and p.curr.line == inx.line: + let min = p.curr; walk p + if likely(isRange()): + walk p, 2 + expect tkInteger: + result.loopItems = ast.newNode(ntIndexRange) + result.loopItems.rangeNodes = [ + ast.newInteger(min.value.parseInt, min), + ast.newInteger(p.curr.value.parseInt, p.curr) + ] + walk p if p.curr is tkColon: walk p while p.curr.isChild(tk): let node = p.getPrefixOrInfix() @@ -814,6 +827,15 @@ prefixHandle pInclude: walk p else: return nil +prefixHandle pImport: + # parse `@import` + if likely p.next is tkString: + let tk = p.curr + walk p + result = ast.newNode(ntImport, tk) + add result.modules, p.curr.value + walk p + prefixHandle pSnippet: case p.curr.kind of tkSnippetJS: @@ -1051,6 +1073,7 @@ proc getPrefixFn(p: var Parser, excludes, includes: set[TokenKind] = {}): Prefix of tkViewLoader: pViewLoader of tkSnippetJS, tkSnippetJSON, tkSnippetYaml: pSnippet of tkInclude: pInclude + of tkImport: pImport of tkClient: pClientSide of tkLB: pAnoArray of tkLC: pAnoObject @@ -1100,6 +1123,7 @@ proc parseRoot(p: var Parser, excludes, includes: set[TokenKind] = {}): Node {.g p.pElement() of tkSnippetJS: p.pSnippet() of tkInclude: p.pInclude() + of tkImport: p.pImport() of tkLB: p.pAnoArray() of tkLC: p.pAnoObject() of tkFN, tkFunc: p.pFunction()