Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
Signed-off-by: George Lemon <[email protected]>
  • Loading branch information
georgelemon committed Jan 12, 2024
1 parent 3a2ecc9 commit 23b959c
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 107 deletions.
40 changes: 24 additions & 16 deletions src/tim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import std/json except `%*`
import std/times

import tim/engine/[meta, parser, compiler, logging]
import pkg/[watchout, kapsis/cli]

import tim/engine/[meta, parser, logging]
import tim/engine/compilers/html

from std/strutils import `%`, indent
from std/os import `/`

Expand All @@ -17,7 +19,7 @@ const
DOCKTYPE = "<!DOCKTYPE html>"
defaultLayout = "base"

proc jitCompiler*(engine: Tim, tpl: TimTemplate, data: JsonNode): HtmlCompiler =
proc jitCompiler*(engine: TimEngine, tpl: TimTemplate, data: JsonNode): HtmlCompiler =
## Compiles `tpl` AST at runtime
newCompiler(engine.readAst(tpl), tpl, engine.isMinified(), engine.getIndentSize(), data)

Expand All @@ -26,7 +28,7 @@ proc displayErrors(l: Logger) =
display(err)
display(l.filePath)

proc compileCode*(engine: Tim, tpl: TimTemplate, refreshAst = false) =
proc compileCode*(engine: TimEngine, tpl: TimTemplate, refreshAst = false) =
# Compiles `tpl` TimTemplate to either `.html` or binary `.ast`
var tplView: TimTemplate
if tpl.getType == ttView:
Expand All @@ -53,7 +55,7 @@ proc compileCode*(engine: Tim, tpl: TimTemplate, refreshAst = false) =
else:
p.logger.displayErrors()

proc precompile*(engine: Tim, callback: TimCallback = nil,
proc precompile*(engine: TimEngine, callback: TimCallback = nil,
flush = true, waitThread = false) =
## Precompiles available templates inside `layouts` and `views`
## directories to either static `.html` or binary `.ast`.
Expand All @@ -68,25 +70,29 @@ proc precompile*(engine: Tim, callback: TimCallback = nil,
when defined timHotCode:
var watchable: seq[string]
# Define callback procs for pkg/watchout

# Callback `onFound`
proc onFound(file: watchout.File) =
# Runs when detecting a new template.
let tpl: TimTemplate = engine.getTemplateByPath(file.getPath())
# if not tpl.isUsed(): return # prevent compiling tpl if not in use
case tpl.getType
of ttView, ttLayout:
engine.compileCode(tpl)
if engine.errors.len > 0:
for err in engine.errors:
echo err
# setLen(engine.errors, 0)
else: discard

# Callback `onChange`
proc onChange(file: watchout.File) =
# Runs when detecting changes
let tpl: TimTemplate = engine.getTemplateByPath(file.getPath())
# echo tpl.isUsed()
# if not tpl.isUsed(): return # prevent compiling tpl if not in use
echo "✨ Changes detected"
echo indent(file.getName() & "\n", 3)
# echo toUnix(getTime())
let tpl: TimTemplate = engine.getTemplateByPath(file.getPath())
case tpl.getType()
of ttView, ttLayout:
engine.compileCode(tpl)
Expand All @@ -96,18 +102,19 @@ proc precompile*(engine: Tim, callback: TimCallback = nil,
else:
for path in tpl.getDeps:
let deptpl = engine.getTemplateByPath(path)
# echo indent($(ttView) / deptpl.getName(), 4)
engine.compileCode(deptpl, refreshAst = true)
if engine.errors.len > 0:
for err in engine.errors:
echo err

# Callback `onDelete`
proc onDelete(file: watchout.File) =
# Runs when deleting a file
echo "✨ Deleted\n", file.getName()
engine.clearTemplateByPath(file.getPath())

var w = newWatchout(@[engine.getSourcePath() / "*"], onChange, onFound, onDelete)
var w = newWatchout(@[engine.getSourcePath() / "*"], onChange,
onFound, onDelete, recursive = true, ext = @["timl"])
w.start(waitThread)
else:
for tpl in engine.getViews():
Expand All @@ -120,7 +127,7 @@ proc precompile*(engine: Tim, callback: TimCallback = nil,
for tpl in engine.getLayouts():
engine.compileCode(tpl)

proc render*(engine: Tim, viewName: string,
proc render*(engine: TimEngine, viewName: string,
layoutName = defaultLayout, global, local = newJObject()): string =
## Renders a view based on `viewName` and `layoutName`.
## Exposing data to a template is possible using `global` or
Expand Down Expand Up @@ -167,15 +174,15 @@ proc render*(engine: Tim, viewName: string,
raise newException(TimError, "View not found: `$1`" % [viewName])

when defined napibuild:
# Setup for building Tim as a node addon via NAPI
# Setup for building TimEngine as a node addon via NAPI
import pkg/denim
from std/sequtils import toSeq

var timjs: Tim
var timjs: TimEngine
init proc(module: Module) =
proc init(src: string, output: string,
basepath: string, minify: bool, indent: int) {.export_napi.} =
## Initialize Tim Engine
## Initialize TimEngine Engine
timjs = newTim(
args.get("src").getStr,
args.get("output").getStr,
Expand All @@ -185,7 +192,7 @@ when defined napibuild:
)

proc precompileSync() {.export_napi.} =
## Precompile Tim templates
## Precompile TimEngine templates
timjs.precompile(flush = true, waitThread = false)

proc renderSync(view: string) {.export_napi.} =
Expand All @@ -194,7 +201,8 @@ when defined napibuild:
return %*(x)

elif not isMainModule:
import tim/engine/[meta, parser, compiler, logging]
import tim/engine/[meta, parser, logging]
import tim/engine/compilers/html

export parser, compiler, json
export meta except Tim
export parser, html, json
export meta except TimEngine
12 changes: 9 additions & 3 deletions src/tim/engine/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import ./tokens
import std/[tables, json, macros]

import kapsis/cli

from std/htmlparser import tagToStr, htmlTag, HtmlTag
export tagToStr, htmlTag, HtmlTag

Expand Down Expand Up @@ -157,11 +159,15 @@ type

Meta* = array[3, int]
ScopeTable* = TableRef[string, Node]
# PartialsTable* = TableRef[string, Ast]
PartialTable* = TableRef[string, Ast]
TimPartialsTable* = TableRef[string, (Ast, seq[cli.Row])]
Ast* = object
src*: string
## trace the source path
nodes*: seq[Node]
partials*: PartialTable
## a seq containing tree nodes
partials*: TimPartialsTable
## other trees resulted from imports
jit*: bool

const ntAssignableSet* = {ntLitString, ntLitInt, ntLitFloat, ntLitBool}

Expand Down
40 changes: 15 additions & 25 deletions src/tim/engine/compiler.nim → src/tim/engine/compilers/html.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,15 @@
import std/[tables, strutils,
json, options, terminal]

import ./ast, ./logging
import ../ast, ../logging

from ./meta import Tim, TimTemplate, TimTemplateType,
from ../meta import TimEngine, TimTemplate, TimTemplateType,
getType, getSourcePath

include ./tim

type
HtmlCompiler* = object
ast: Ast
tpl: TimTemplate
nl: string = "\n"
output: string
jsOutput: string
jsCodeExists: bool
start: bool
case tplType: TimTemplateType
of ttLayout:
head: string
else: discard
logger*: Logger
indent: int = 2
minify, hasErrors: bool
stickytail: bool
# when `false` inserts a `\n` char
# before closing the HTML element tag.
# Does not apply to `textarea`, `button` and other
# self closing tags (such as `submit`, `img` and so on)
HtmlCompiler* = object of TimCompiler
when not defined timStandalone:
globalScope: ScopeTable = ScopeTable()
data: JsonNode
Expand Down Expand Up @@ -160,7 +143,6 @@ proc toString(value: Value): string =
value.nVal.toString()

proc print(val: Node) =
echo val
let meta = " ($1:$2) " % [$val.meta[0], $val.meta[2]]
stdout.styledWriteLine(
fgGreen, "Debug",
Expand Down Expand Up @@ -297,10 +279,11 @@ proc infixEvaluator(c: var HtmlCompiler, lhs, rhs: Node,
else: discard
of ntIdent:
var lhs = c.fromScope(lhs.identName, scopetables)
if lhs == nil or rhs == nil: return # false
case rhs.nt
of ntIdent:
var rhs = c.fromScope(rhs.identName, scopetables)
if lhs != nil and rhs != nil:
if rhs != nil:
result = c.infixEvaluator(lhs.varValue, rhs.varValue, infixOp, scopetables)
else:
result = c.infixEvaluator(lhs.varValue, rhs, infixOp, scopetables)
Expand Down Expand Up @@ -425,17 +408,23 @@ template evalBranch(branch: Node, body: untyped) =
of ntInfixExpr, ntMathInfixExpr:
if c.infixEvaluator(branch.infixLeft, branch.infixRight,
branch.infixOp, scopetables):
newScope(scopetables)
body
clearScope(scopetables)
return # condition is thruty
of ntIdent:
if c.infixEvaluator(branch, boolDefault, EQ, scopetables):
newScope(scopetables)
body
clearScope(scopetables)
return # condition is thruty
of ntDotExpr:
let x = c.dotEvaluator(branch, scopetables)
if likely(x != nil):
if c.infixEvaluator(x, boolDefault, EQ, scopetables):
newScope(scopetables)
body
clearScope(scopetables)
return
else: discard

Expand Down Expand Up @@ -610,7 +599,7 @@ proc htmlElement(c: var HtmlCompiler, node: Node, scopetables: var seq[ScopeTabl
proc evaluatePartials(c: var HtmlCompiler, includes: seq[string], scopetables: var seq[ScopeTable]) =
for x in includes:
if likely(c.ast.partials.hasKey(x)):
c.evaluateNodes(c.ast.partials[x].nodes, scopetables)
c.evaluateNodes(c.ast.partials[x][0].nodes, scopetables)

proc evaluateNodes(c: var HtmlCompiler, nodes: seq[Node], scopetables: var seq[ScopeTable]) =
for i in 0..nodes.high:
Expand All @@ -634,6 +623,7 @@ proc evaluateNodes(c: var HtmlCompiler, nodes: seq[Node], scopetables: var seq[S
of ntAssignExpr:
c.assignExpr(nodes[i], scopetables)
of ntConditionStmt:
# echo nodes[i]
c.evalCondition(nodes[i], scopetables)
of ntLoopStmt:
c.evalLoop(nodes[i], scopetables)
Expand Down
21 changes: 21 additions & 0 deletions src/tim/engine/compilers/tim.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type
TimCompiler* = object of RootObj
ast: Ast
tpl: TimTemplate
nl: string = "\n"
output: string
jsOutput: string
jsCodeExists: bool
start: bool
case tplType: TimTemplateType
of ttLayout:
head: string
else: discard
logger*: Logger
indent: int = 2
minify, hasErrors: bool
stickytail: bool
# when `false` inserts a `\n` char
# before closing the HTML element tag.
# Does not apply to `textarea`, `button` and other
# self closing tags (such as `submit`, `img` and so on)
7 changes: 7 additions & 0 deletions src/tim/engine/logging.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type
duplicateAttribute = "Duplicate HTML attribute $"
duplicateField = "Duplicate field $"
undeclaredField = "Undeclared field $"
importNotFound = "Cannot open file: $"
internalError = "$"

Level* = enum
Expand Down Expand Up @@ -142,6 +143,12 @@ template error*(msg: Message, tk: TokenTuple, strFmt: bool,
p.hasErrors = true
return # block code execution

template error*(msg: Message, meta: Meta, args: varargs[string]) =
if not p.hasErrors:
p.logger.newError(msg, meta[0], meta[2], true, args)
p.hasErrors = true
return # block code execution

template errorWithArgs*(msg: Message, tk: TokenTuple, args: openarray[string]) =
if not p.hasErrors:
p.logger.newError(msg, tk.line, tk.pos, true, args)
Expand Down
Loading

0 comments on commit 23b959c

Please sign in to comment.