Skip to content

Commit

Permalink
make objects iterable + other checks
Browse files Browse the repository at this point in the history
Signed-off-by: George Lemon <[email protected]>
  • Loading branch information
georgelemon committed Feb 28, 2024
1 parent 7ab5e47 commit d2ed15f
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 25 deletions.
5 changes: 4 additions & 1 deletion src/tim/engine/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type
ntCommandStmt = "CommandStatement"
ntIdent = "Identifier"
ntCall = "FunctionCall"
ntIdentPair
ntDotExpr
ntBracketExpr
ntConditionStmt = "ConditionStatement"
Expand Down Expand Up @@ -119,9 +120,11 @@ type
condElifBranch*: seq[ConditionBranch]
condElseBranch*: seq[Node]
of ntLoopStmt:
loopItem*: Node
loopItem*: Node # ntIdent or ntIdentPair
loopItems*: Node
loopBody*: seq[Node]
of ntIdentPair:
identPairs*: tuple[a, b: Node]
of ntLitString:
sVal*: string
sVals*: seq[Node]
Expand Down
81 changes: 57 additions & 24 deletions src/tim/engine/compilers/html.nim
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ proc toString(node: Node, escape = false): string =
fromJson(jsony.toJson(node.objectItems)).pretty
of ntLitArray:
fromJson(jsony.toJson(node.arrayItems)).pretty
of ntIdent: node.identName
else: ""
if escape:
result = xmltree.escape(result)
Expand Down Expand Up @@ -281,27 +282,33 @@ proc walkAccessorStorage(c: var HtmlCompiler,
lhs, rhs: Node, scopetables: var seq[ScopeTable]): Node =
case lhs.nt
of ntLitObject:
try:
result = lhs.objectItems[rhs.identName]
except KeyError:
compileErrorWithArgs(undeclaredField, rhs.meta, [rhs.identName])
case rhs.nt
of ntIdent:
try:
result = lhs.objectItems[rhs.identName]
except KeyError:
compileErrorWithArgs(undeclaredField, rhs.meta, [rhs.identName])
else: compileErrorWithArgs(invalidAccessorStorage, rhs.meta, [rhs.toString, $lhs.nt])
of ntDotExpr:
let x = c.walkAccessorStorage(lhs.lhs, lhs.rhs, scopetables)
if likely(x != nil):
return c.walkAccessorStorage(x, rhs, scopetables)
of ntIdent:
let x = c.fromScope(lhs.identName, scopetables)
let x = c.getValue(lhs, scopetables)
if likely(x != nil):
result = c.walkAccessorStorage(x.varValue, rhs, scopetables)
result = c.walkAccessorStorage(x, rhs, scopetables)
of ntBracketExpr:
let lhs = c.bracketEvaluator(lhs, scopetables)
if likely(lhs != nil):
return c.walkAccessorStorage(lhs, rhs, scopetables)
of ntLitArray:
try:
result = lhs.arrayItems[rhs.iVal]
except Defect:
compileErrorWithArgs(indexDefect, lhs.meta, [$(rhs.iVal), "0.." & $(lhs.arrayItems.high)])
case rhs.nt
of ntLitInt:
try:
result = lhs.arrayItems[rhs.iVal]
except Defect:
compileErrorWithArgs(indexDefect, lhs.meta, [$(rhs.iVal), "0.." & $(lhs.arrayItems.high)])
else: compileErrorWithArgs(invalidAccessorStorage, rhs.meta, [rhs.toString, $lhs.nt])
else: discard

proc dotEvaluator(c: var HtmlCompiler, node: Node,
Expand All @@ -324,7 +331,8 @@ proc bracketEvaluator(c: var HtmlCompiler, node: Node,
result = x.toTimNode
of scopeStorage:
let index = c.getValue(node.bracketIndex, scopetables)
return c.walkAccessorStorage(node.bracketLHS, index, scopetables)
if likely(index != nil):
return c.walkAccessorStorage(node.bracketLHS, index, scopetables)

proc writeDotExpr(c: var HtmlCompiler, node: Node, scopetables: var seq[ScopeTable]) =
# Handle dot expressions
Expand Down Expand Up @@ -754,32 +762,57 @@ proc evalConcat(c: var HtmlCompiler, node: Node, scopetables: var seq[ScopeTable
write x, true, false
write y, true, false

template loopEvaluator(items: Node) =
template loopEvaluator(kv, items: Node) =
case items.nt:
of ntLitString:
of ntLitString:
case kv.nt
of ntVariableDef:
for x in items.sVal:
newScope(scopetables)
node.loopItem.varValue = ast.Node(nt: ntLitString, sVal: $(x))
c.varExpr(node.loopItem, scopetables)
c.walkNodes(node.loopBody, scopetables)
clearScope(scopetables)
of ntLitArray:
node.loopItem.varValue = nil
else: discard # todo error
of ntLitArray:
case kv.nt
of ntVariableDef:
for x in items.arrayItems:
newScope(scopetables)
node.loopItem.varValue = x
c.varExpr(node.loopItem, scopetables)
c.walkNodes(node.loopBody, scopetables)
clearScope(scopetables)
of ntLitObject:
node.loopItem.varValue = nil
else: discard # todo error
of ntLitObject:
case kv.nt
of ntVariableDef:
for x, y in items.objectItems:
newScope(scopetables)
node.loopItem.varValue = y
c.varExpr(node.loopItem, scopetables)
c.walkNodes(node.loopBody, scopetables)
clearScope(scopetables)
else:
let x = @[ntLitString, ntLitArray, ntLitObject]
compileErrorWithArgs(typeMismatch, [$(items.nt), x.join(" ")])
node.loopItem.varValue = nil
of ntIdentPair:
for x, y in items.objectItems:
newScope(scopetables)
let kvar = ast.newNode(ntLitString)
kvar.sVal = x
node.loopItem.identPairs[0].varValue = kvar
node.loopItem.identPairs[1].varValue = y
c.varExpr(node.loopItem.identPairs[0], scopetables)
c.varExpr(node.loopItem.identPairs[1], scopetables)
c.walkNodes(node.loopBody, scopetables)
clearScope(scopetables)
node.loopItem.identPairs[0].varValue = nil
node.loopItem.identPairs[1].varValue = nil
else: discard
else:
let x = @[ntLitString, ntLitArray, ntLitObject]
compileErrorWithArgs(typeMismatch, [$(items.nt), x.join(" ")])

proc evalLoop(c: var HtmlCompiler, node: Node,
scopetables: var seq[ScopeTable]) =
Expand All @@ -789,19 +822,19 @@ proc evalLoop(c: var HtmlCompiler, node: Node,
let some = c.getScope(node.loopItems.identName, scopetables)
if likely(some.scopeTable != nil):
let items = some.scopeTable[node.loopItems.identName]
loopEvaluator(items.varValue)
loopEvaluator(node.loopItem, items.varValue)
else: compileErrorWithArgs(undeclaredVariable, [node.loopItems.identName])
of ntDotExpr:
let items = c.dotEvaluator(node.loopItems, scopetables)
if likely(items != nil):
loopEvaluator(items)
loopEvaluator(node.loopItem, items)
else:
compileErrorWithArgs(undeclaredVariable, [node.loopItems.lhs.identName])
of ntLitArray:
loopEvaluator(node.loopItems)
loopEvaluator(node.loopItem, node.loopItems)
of ntBracketExpr:
let items = c.bracketEvaluator(node.loopItems, scopetables)
loopEvaluator(items)
loopEvaluator(node.loopItem, items)
else:
compileErrorWithArgs(invalidIterator)

Expand Down Expand Up @@ -1044,8 +1077,8 @@ proc evaluatePartials(c: var HtmlCompiler, includes: seq[string], scopetables: v
if likely(c.ast.partials.hasKey(x)):
c.walkNodes(c.ast.partials[x][0].nodes, scopetables)

proc walkNodes(c: var HtmlCompiler, nodes: seq[Node],
scopetables: var seq[ScopeTable], parentNodeType: NodeType = ntUnknown): Node {.discardable.} =
proc walkNodes(c: var HtmlCompiler, nodes: seq[Node], scopetables: var seq[ScopeTable],
parentNodeType: NodeType = ntUnknown): Node {.discardable.} =
# Evaluate a seq[Node] nodes
for i in 0..nodes.high:
case nodes[i].nt
Expand Down
1 change: 1 addition & 0 deletions src/tim/engine/logging.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type
invalidIndentation = "Invalid indentation"
unexpectedToken = "Unexpected token $"
undeclaredVariable = "Undeclared variable $"
invalidAccessorStorage = "Invalid accessor storage $ for $"
varRedefine = "Attempt to redefine variable $"
varImmutable = "Attempt to reassign value to immutable constant $"
fnRedefine = "Attempt to redefine function $"
Expand Down
11 changes: 11 additions & 0 deletions src/tim/engine/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,17 @@ prefixHandle pFor:
result.loopItem.varName = p.curr.value
result.loopItem.varImmutable = true
walk p
if p.curr is tkComma and p.next in {tkIdentVar, tkIdentVarSafe}:
walk p
let pairNode = ast.newNode(ntIdentPair, p.curr)
pairNode.identPairs[0] = result.loopItem
var vNode: Node
vNode = ast.newNode(ntVariableDef, p.curr)
vNode.varName = p.curr.value
vNode.varImmutable = true
pairNode.identPairs[1] = vNode
result.loopItem = pairNode
walk p
expectWalk(tkIN)
expect {tkIdentVar, tkLB}:
let items = p.parsePrefix()
Expand Down

0 comments on commit d2ed15f

Please sign in to comment.