From 434be690febc31b32d2b2f74fd9af595e73d186e Mon Sep 17 00:00:00 2001 From: George Lemon Date: Thu, 28 Mar 2024 19:54:07 +0200 Subject: [PATCH] stdlib work Signed-off-by: George Lemon --- src/tim.nim | 83 +++++++++++++++++- src/tim/engine/ast.nim | 30 ++++++- src/tim/engine/compilers/html.nim | 72 ++++++++++------ src/tim/engine/meta.nim | 8 +- src/tim/engine/parser.nim | 33 +++++--- src/tim/engine/{stdlib.nim => std.nim} | 111 +++++++++++++------------ 6 files changed, 241 insertions(+), 96 deletions(-) rename src/tim/engine/{stdlib.nim => std.nim} (81%) diff --git a/src/tim.nim b/src/tim.nim index fe0e414..03625a6 100755 --- a/src/tim.nim +++ b/src/tim.nim @@ -10,7 +10,7 @@ import std/[times, options, asyncdispatch, import pkg/[watchout, httpx, websocketx] import pkg/kapsis/cli -import tim/engine/[meta, parser, logging] +import tim/engine/[meta, parser, logging, std] import tim/engine/compilers/html from std/strutils import `%`, indent, split, parseInt, join @@ -21,8 +21,8 @@ from std/xmltree import escape const DOCKTYPE = "" defaultLayout = "base" - -const localStorage* = CacheSeq"LocalStorage" + localStorage* = CacheSeq"LocalStorage" + # Compile-time Cache seq to handle local data macro initCommonStorage*(x: untyped) = ## Initializes a common localStorage that can be @@ -412,8 +412,83 @@ when defined napibuild: elif not isMainModule: # Expose Tim Engine API for Nim development (as a Nimble librayr) - export parser, html, json + import std/enumutils + import tim/engine/ast + + export ast, parser, html, json, stdlib export meta except TimEngine + export localModule, SourceCode, Arg, NodeType + + proc initModule(modules: NimNode): NimNode = + result = newStmtList() + var functions: seq[string] + modules.expectKind nnkArgList + for mblock in modules[0]: + mblock.expectKind nnkBlockStmt + for m in mblock[1]: + case m.kind + of nnkProcDef: + let id = m[0] + var fn = "fn " & $m[0] & "*(" + var fnReturnType: NodeType + var params: seq[string] + if m[3][0].kind != nnkEmpty: + for p in m[3][1..^1]: + add params, $p[0] & ":" & $p[1] + add fn, params.join(",") + add fn, "): " + add fn, $m[3][0] + fnReturnType = ast.getType(m[3][0]) + else: + add fn, ")" + add functions, fn + var lambda = nnkLambda.newTree(newEmptyNode(), newEmptyNode(), newEmptyNode()) + var procParams = newNimNode(nnkFormalParams) + procParams.add( + ident("Node"), + nnkIdentDefs.newTree( + ident("args"), + nnkBracketExpr.newTree( + ident("openarray"), + ident("Arg") + ), + newEmptyNode() + ), + nnkIdentDefs.newTree( + ident("returnType"), + ident("NodeType"), + ident(symbolName(ntLitString)) + ) + ) + add lambda, procParams + add lambda, newEmptyNode() + add lambda, newEmptyNode() + add lambda, m[6] + add result, + newAssignment( + nnkBracketExpr.newTree( + ident"localModule", newLit($id) + ), + lambda + ) + else: + add result, m + add result, + newAssignment( + nnkBracketExpr.newTree( + ident("stdlib"), + newLit("*") + ), + nnkTupleConstr.newTree( + ident("localModule"), + newCall(ident("SourceCode"), newLit(functions.join("\n"))) + ) + ) + echo result.repr + + + macro initLocalModule*(x: varargs[untyped]): untyped = + initModule(x) else: # Build Tim Engine as a standalone CLI application diff --git a/src/tim/engine/ast.nim b/src/tim/engine/ast.nim index 7a9fd5d..9d00630 100755 --- a/src/tim/engine/ast.nim +++ b/src/tim/engine/ast.nim @@ -27,6 +27,7 @@ type ntLitArray = "array" ntLitObject = "object" ntFunction = "function" + ntLitVoid = "void" ntVariableDef = "Variable" ntAssignExpr = "Assignment" @@ -53,6 +54,12 @@ type ntJsonSnippet = "JsonSnippet" ntClientBlock = "ClientSideStatement" ntStmtList = "StatementList" + ntRuntimeCode = "Runtime" + + FunctionType* = enum + fnImportLocal + fnImportSystem + fnImportModule CommandType* = enum cmdEcho = "echo" @@ -214,7 +221,8 @@ type ## if a function has no return type, then `ntUnknown` ## is used as default (void) fnReturnHtmlElement*: HtmlTag - fnFwdDecl*, fnExport*, fnImportNim*: bool + fnFwdDecl*, fnExport*: bool + fnType*: FunctionType fnSource*: string of ntJavaScriptSnippet, ntYamlSnippet, ntJsonSnippet: @@ -248,6 +256,8 @@ type ## on the fly for templates marked as jit. of ntStmtList: stmtList*: seq[Node] + of ntRuntimeCode: + runtimeCode*: string else: discard meta*: Meta @@ -439,6 +449,21 @@ proc getTag*(x: Node): string = of tagWbr: "wbr" else: x.stag # tagUnknown +proc getType*(x: NimNode): NodeType {.compileTime.} = + if x.strVal == "string": + return ntLitString + if x.strVal == "int": + return ntLitInt + if x.strVal == "float": + return ntLitFloat + if x.strVal == "bool": + return ntLitBool + if x.strVal == "object": + return ntLitObject + if x.strVal == "array": + return ntLitArray + result = ntUnknown + # # AST to JSON convertors # @@ -510,6 +535,9 @@ proc newBool*(v: bool): Node = result = newNode(ntLitBool) result.bVal = v +var voidNode = newNode(ntLitVoid) +proc getVoidNode*(): Node = voidNode + proc newVariable*(varName: string, varValue: Node, meta: Meta): Node = ## Create a new variable definition Node result = newNode(ntVariableDef) diff --git a/src/tim/engine/compilers/html.nim b/src/tim/engine/compilers/html.nim index 830ba67..c4b2e67 100755 --- a/src/tim/engine/compilers/html.nim +++ b/src/tim/engine/compilers/html.nim @@ -8,7 +8,7 @@ import std/[tables, strutils, json, jsonutils, options, terminal, sequtils] import pkg/jsony -import ./tim, ../stdlib +import ./tim, ../std, ../parser from std/xmltree import escape from ../meta import TimEngine, TimTemplate, TimTemplateType, @@ -88,7 +88,7 @@ const domSetAttribute = "$1.setAttribute('$2','$3');" domInsertAdjacentElement = "$1.insertAdjacentElement('beforeend',$2);" domInnerText = "$1.innerText=\"$2\";" - stdlibPaths = ["std/system", "std/strings", "std/arrays", "std/os"] + stdlibPaths = ["std/system", "std/strings", "std/arrays", "std/os", "*"] when not defined timStandalone: # Scope API, available for library version of TimEngine @@ -110,7 +110,7 @@ when not defined timStandalone: else: c.globalScope[node.varName] = node of ntFunction: - if c.ast.src notin stdlibPaths: + if node.fnSource notin stdlibPaths: if scopetables.len > 0: scopetables[^1][node.fnIdent] = node else: c.globalScope[node.fnIdent] = node @@ -470,12 +470,15 @@ proc bracketEvaluator(c: var HtmlCompiler, node: Node, scopetables: var seq[ScopeTable]): Node = case node.bracketStorageType of localStorage, globalStorage: - let x = c.evalStorage(node) - if likely(x != nil): - result = x.toTimNode + let index = c.getValue(node.bracketIndex, scopetables) + notnil index: + var x = c.evalStorage(node.bracketLHS) + notnil x: + result = x.toTimNode + return c.walkAccessorStorage(result, index, scopetables) of scopeStorage: let index = c.getValue(node.bracketIndex, scopetables) - if likely(index != nil): + notnil index: result = c.walkAccessorStorage(node.bracketLHS, index, scopetables) proc writeDotExpr(c: var HtmlCompiler, @@ -498,7 +501,7 @@ proc evalCmd(c: var HtmlCompiler, node: Node, return node.cmdValue else: var val = c.getValue(node.cmdValue, scopetables) - if val != nil: + notnil val: case node.cmdType of cmdEcho: val.meta = node.cmdValue.meta @@ -996,7 +999,7 @@ template loopEvaluator(kv, items: Node) = of ntLitObject: case kv.nt of ntVariableDef: - for x, y in items.objectItems: + for k, y in items.objectItems: newScope(scopetables) node.loopItem.varValue = y c.varExpr(node.loopItem, scopetables) @@ -1039,8 +1042,15 @@ proc evalLoop(c: var HtmlCompiler, node: Node, of ntIdent: let some = c.getScope(node.loopItems.identName, scopetables) if likely(some.scopeTable != nil): - let items = some.scopeTable[node.loopItems.identName] - loopEvaluator(node.loopItem, items.varValue) + var items: Node + case some.scopeTable[node.loopItems.identName].nt + of ntFunction: + items = c.unsafeCall(node.loopItems, + some.scopeTable[node.loopItems.identName], scopetables) + of ntVariableDef: + items = some.scopeTable[node.loopItems.identName].varValue + else: discard # error ? + loopEvaluator(node.loopItem, items) else: compileErrorWithArgs(undeclaredVariable, [node.loopItems.identName]) of ntDotExpr: let items = c.dotEvaluator(node.loopItems, scopetables) @@ -1160,12 +1170,8 @@ proc fnDef(c: var HtmlCompiler, node: Node, if p.pImplVal.nt != p.pType: compileErrorWithArgs(typeMismatch, [$(p.pImplVal.nt), $p.pType], p.meta) - # if node.fnReturnType != ntUnknown: - # check if function has a return type - # where tkUnknown acts like a void c.stack(node.fnIdent, node, scopetables) else: - # if node.fnParams compileErrorWithArgs(fnRedefine, [node.fnIdent]) proc unsafeCall(c: var HtmlCompiler, node, fnNode: Node, @@ -1177,20 +1183,34 @@ proc unsafeCall(c: var HtmlCompiler, node, fnNode: Node, # is matching the total number of parameters if node.identArgs.len > 0: var i = 0 - if fnNode.fnImportNim: - var args: seq[stdlib.Arg] + if fnNode.fnType in {fnImportSystem, fnImportModule}: + var args: seq[std.Arg] for i in 0..node.identArgs.high: try: let param = fnNode.fnParams[params[i]] let argValue = c.getValue(node.identArgs[i], scopetables) - if c.typeCheck(argValue, param[1]): - add args, (param[0][1..^1], argValue) - else: return # typeCheck returns `typeMismatch` + notnil argValue: + if c.typeCheck(argValue, param[1]): + add args, (param[0][1..^1], argValue) + else: return # typeCheck returns `typeMismatch` + do: + compileErrorWithArgs(fnReturnVoid, ["?"]) except Defect: compileErrorWithArgs(fnExtraArg, [node.identName, $(params.len), $(node.identArgs.len)]) try: - return stdlib.call(fnNode.fnSource, node.identName, args) + result = std.call(fnNode.fnSource, node.identName, args) + if result != nil: + case result.nt + of ntRuntimeCode: + {.gcsafe.}: + var p: Parser = parser.parseSnippet("", result.runtimeCode) + let phc = newCompiler(p.getAst) + if not phc.hasErrors: + add c.output, phc.getHtml() + return nil + else: discard + return # result except SystemModule as e: compileErrorWithArgs(internalError, [e.msg, fnNode.fnSource, fnNode.fnIdent], node.meta) @@ -1436,10 +1456,11 @@ proc walkNodes(c: var HtmlCompiler, nodes: seq[Node], # if parentNodeType != ntFunction and x.nt != ntHtmlElement: # compileErrorWithArgs(fnReturnMissingCommand, [node.identName, $(x.nt)]) let x: Node = c.getValue(node, scopetables) - if not c.isClientSide: - write x, true, node.identSafe - else: - add c.jsOutputCode, domInnerText % [xel, x.toString()] + notnil x: + if not c.isClientSide: + write x, true, node.identSafe + else: + add c.jsOutputCode, domInnerText % [xel, x.toString()] of ntDotExpr: let x: Node = c.dotEvaluator(node, scopetables) if not c.isClientSide: @@ -1565,7 +1586,6 @@ else: ) if minify: setLen(result.nl, 0) var scopetables = newSeq[ScopeTable]() - result.walkNodes(result.ast.nodes, scopetables) proc newCompiler*(ast: Ast, minify = true, indent = 2): HtmlCompiler = diff --git a/src/tim/engine/meta.nim b/src/tim/engine/meta.nim index 40938a3..c0b0d93 100755 --- a/src/tim/engine/meta.nim +++ b/src/tim/engine/meta.nim @@ -4,7 +4,8 @@ # Made by Humans from OpenPeeps # https://github.com/openpeeps/tim -import std/[macros, os, json, strutils, sequtils, base64, tables] +import std/[macros, os, json, + strutils, sequtils, base64, tables] import pkg/[checksums/md5, flatty] export getProjectPath @@ -38,6 +39,10 @@ type TemplateTable = TableRef[string, TimTemplate] TimCallback* = proc() {.nimcall, gcsafe.} + + TimPolicy* = ref object + # todo + TimEngine* = ref object base, src, output: string minify, htmlErrors: bool @@ -46,6 +51,7 @@ type errors*: seq[string] placeholders: Table[string, seq[Ast]] ## A table containing available placeholders + policy: TimPolicy when defined timStandalone: globals: Globals else: diff --git a/src/tim/engine/parser.nim b/src/tim/engine/parser.nim index 7a1691b..73c3565 100755 --- a/src/tim/engine/parser.nim +++ b/src/tim/engine/parser.nim @@ -5,11 +5,11 @@ # https://github.com/openpeeps/tim {.warning[ImplicitDefaultValue]:off.} -import std/[macros, streams, lexbase, +import std/[macros, macrocache, streams, lexbase, strutils, sequtils, re, tables, os, with] import ./meta, ./tokens, ./ast, ./logging -import ./stdlib +import ./std import pkg/kapsis/cli import pkg/importer @@ -718,7 +718,7 @@ prefixHandle pFor: walk p let inx = p.curr expectWalk tkIN - if p.curr in {tkIdentVar, tkString, tkLB}: + if p.curr in {tkIdentVar, tkString, tkLB} or p.isFnCall: # expect {tkIdentVar, tkString, tkLB, tkInteger}: # todo function call let items = p.parsePrefix() caseNotNil items: @@ -935,7 +935,7 @@ prefixHandle pFunction: else: break elif p.curr is tkAssign: result.fnParams[pName.value] = - (pName.value, ntUnknown, nil, [0, 0, 0]) + (pName.value, ntLitVoid, nil, [0, 0, 0]) handleImplicitDefaultValue() result.fnParams[pName.value].meta = implNode.meta if p.curr is tkComma and p.next isnot tkRP: @@ -954,6 +954,9 @@ prefixHandle pFunction: result.fnReturnHtmlElement = htmlTag(p.curr.value) walk p; expectWalk(tkRB) else: discard # todo error + of tkLitVoid: + result.fnReturnType = ntLitVoid + walk p else: expect tkTypedLiterals: # set a return type @@ -971,9 +974,11 @@ prefixHandle pFunction: if unlikely(result.fnBody.len == 0): error(badIndentation, p.curr) else: - result.fnImportNim = p.tree.src.startsWith("std/") - if result.fnImportNim: - result.fnSource = p.tree.src + if p.tree.src == "*": + result.fnType = FunctionType.fnImportModule + elif p.tree.src.startsWith("std"): + result.fnType = FunctionType.fnImportSystem + result.fnSource = p.tree.src result.fnFwdDecl = true prefixHandle pFunctionCall: @@ -1126,6 +1131,8 @@ proc parseRoot(p: var Parser, excludes, includes: set[TokenKind] = {}): Node {.g of tkIdentVar, tkIdentVarSafe: if p.next is tkAssign: p.pIdentOrAssignment() + elif p.next is tkDot: + p.pIdent() else: nil of tkIF: p.pCondition() of tkCase: p.pCase() @@ -1241,6 +1248,8 @@ proc parseModule(engine: TimEngine, moduleName: string, p.logger.newError(internalError, p.curr.line, p.curr.col, false, p.lex.getError) if unlikely(p.hasErrors): + echo p.logger.errors.toSeq + echo moduleName break let node = p.parseRoot() if node != nil: @@ -1251,13 +1260,13 @@ proc parseModule(engine: TimEngine, moduleName: string, proc initSystemModule(p: var Parser) = ## Make `std/system` available by default {.gcsafe.}: - let stdsystem = "std/system" + let x= "std/system" var sysNode = ast.newNode(ntImport) - sysNode.modules.add(stdsystem) + sysNode.modules.add(x) p.tree.nodes.add(sysNode) p.tree.modules = TimModulesTable() - p.tree.modules[stdsystem] = - p.engine.parseModule(stdsystem, std(stdsystem)[1]) + p.tree.modules[x] = + p.engine.parseModule(x, std(x)[1]) # var L = initTicketLock() # parseHandle[Parser](sysid, dirPath(p.tpl.sources), addr(p.imports), @@ -1281,7 +1290,7 @@ proc newParser*(engine: TimEngine, tpl: TimTemplate, tpl = tpl isMain = isMainParser refreshAst = refreshAst - initstdlib() + initModuleSystem() p.handle.initSystemModule() startParse(tpl.sources.src) if isMainParser: diff --git a/src/tim/engine/stdlib.nim b/src/tim/engine/std.nim similarity index 81% rename from src/tim/engine/stdlib.nim rename to src/tim/engine/std.nim index fa95c6c..fb8024b 100644 --- a/src/tim/engine/stdlib.nim +++ b/src/tim/engine/std.nim @@ -4,24 +4,24 @@ # Made by Humans from OpenPeeps # https://github.com/openpeeps/bro -import std/[macros, enumutils, critbits] -import ./ast - -# std lib dependencies +import std/[macros, macrocache, enumutils, + critbits, os, math, fenv, strutils, + sequtils, random, unicode, json, base64] import pkg/[jsony, nyml] -import std/[os, math, fenv, strutils, sequtils, - random, unicode, json, base64] -# import ./css +import ./ast, ./meta + +# const + # localModules* = CacheSeq"LocalModules" + # Compile-time Cache seq to handle local modules type Arg* = tuple[name: string, value: Node] - NimCall* = proc(args: openarray[Arg], returnType: NodeType = ntUnknown): Node + NimCall* = proc(args: openarray[Arg], returnType: NodeType = ntLitVoid): Node Module = CritBitTree[NimCall] SourceCode* = distinct string - - Stdlib* = CritBitTree[(Module, SourceCode)] + Stdlib = CritBitTree[(Module, SourceCode)] StringsModule* = object of CatchableError ArraysModule* = object of CatchableError @@ -37,7 +37,7 @@ var critbitsModule {.threadvar.}, systemModule {.threadvar.}, mathModule {.threadvar.}, - chromaModule {.threadvar.}: Module + localModule* {.threadvar.}: Module proc toNimSeq*(node: Node): seq[string] = for item in node.arrayItems: @@ -66,19 +66,20 @@ macro initStandardLibrary() = wrapper: NimNode # wraps nim function hasWrapper: bool - loadFrom: string + src: string - proc addFunction(id: string, args: openarray[(NodeType, string)], nt: NodeType): string = + proc addFunction(id: string, + args: openarray[(NodeType, string)], nt: NodeType): string = var p = args.map do: proc(x: (NodeType, string)): string = "$1: $2" % [x[1], $(x[0])] result = "fn $1*($2): $3\n" % [id, p.join(", "), $nt] proc fwd(id: string, returns: NodeType, args: openarray[(NodeType, string)] = [], - alias = "", wrapper: NimNode = nil, loadFrom = ""): Forward = + alias = "", wrapper: NimNode = nil, src = ""): Forward = Forward(id: id, returns: returns, args: args.toSeq, alias: alias, wrapper: wrapper, hasWrapper: wrapper != nil, - loadFrom: loadFrom) + src: src) # proc `*`(nt: NodeType, count: int): seq[NodeType] = # for i in countup(1, count): @@ -118,8 +119,6 @@ macro initStandardLibrary() = template systemInc: untyped = inc args[0].value.iVal - echo args[0].value - args[0].value template convertToString: untyped = var str: ast.Node @@ -132,6 +131,11 @@ macro initStandardLibrary() = else: discard str + template parseCode: untyped = + var xast: Node = ast.newNode(ntRuntimeCode) + xast.runtimeCode = args[0].value.sVal + xast + let fnSystem = @[ # fwd("json", ntStream, [(ntLitString, "path")], wrapper = getAst(systemStreamFunction())), @@ -139,10 +143,12 @@ macro initStandardLibrary() = fwd("rand", ntLitInt, [(ntLitInt, "max")], "random", wrapper = getAst(systemRandomize())), fwd("len", ntLitInt, [(ntLitString, "x")]), # fwd("len", ntLitInt, [(ntLitArray, "x")]), - fwd("encode", ntLitString, [(ntLitString, "x")], loadFrom = "base64"), - fwd("decode", ntLitString, [(ntLitString, "x")], loadFrom = "base64"), - fwd("toString", ntLitString, [(ntLitInt, "x")], wrapper = getAst(convertToString())) - # fwd("int", ntInt, [(ntLitInt, "x")], "increment", wrapper = getAst(systemInc())), + fwd("encode", ntLitString, [(ntLitString, "x")], src = "base64"), + fwd("decode", ntLitString, [(ntLitString, "x")], src = "base64"), + fwd("toString", ntLitString, [(ntLitInt, "x")], wrapper = getAst(convertToString())), + fwd("timl", ntLitString, [(ntLitString, "x")], wrapper = getAst(parseCode())), + fwd("inc", ntLitVoid, [(ntLitInt, "x")], wrapper = getAst(systemInc())), + fwd("dec", ntLitVoid, [(ntLitInt, "x")]), ] let @@ -150,8 +156,8 @@ macro initStandardLibrary() = fwd("ceil", ntLitFloat, [(ntLitFloat, "x")]), # fwd("clamp") need to add support for ranges fwd("floor", ntLitFloat, [(ntLitFloat, "x")]), - fwd("max", ntLitInt, [(ntLitInt, "x"), (ntLitInt, "y")], loadFrom = "system"), - fwd("min", ntLitInt, [(ntLitInt, "x"), (ntLitInt, "y")], loadFrom = "system"), + fwd("max", ntLitInt, [(ntLitInt, "x"), (ntLitInt, "y")], src = "system"), + fwd("min", ntLitInt, [(ntLitInt, "x"), (ntLitInt, "y")], src = "system"), fwd("round", ntLitFloat, [(ntLitFloat, "x")]), # fwd("abs", ntLitInt, [(ntLitInt, "x")]), fwd("hypot", ntLitFloat, [(ntLitFloat, "x"), (ntLitFloat, "y")]), @@ -182,7 +188,7 @@ macro initStandardLibrary() = fwd("contains", ntLitBool, [(ntLitString, "s"), (ntLitString, "sub")]), fwd("parseBool", ntLitBool, [(ntLitString, "s")]), fwd("parseInt", ntLitInt, [(ntLitString, "s")]), - fwd("parseFloat", ntLitFloat, [(ntLitString, "s")], "toFloat"), + fwd("parseFloat", ntLitFloat, [(ntLitString, "s")]), fwd("format", ntLitString, [(ntLitString, "s"), (ntLitArray, "a")], wrapper = getAst(formatWrapper())) ] @@ -204,7 +210,8 @@ macro initStandardLibrary() = template arraysPop: untyped = try: - delete(args[0].value.arrayItems, args[0].value.arrayItems.high) + delete(args[0].value.arrayItems, + args[0].value.arrayItems.high) except IndexDefect as e: raise newException(ArraysModule, e.msg) @@ -213,7 +220,8 @@ macro initStandardLibrary() = shuffle(args[0].value.arrayItems) template arraysJoin: untyped = - ast.newString(strutils.join(toNimSeq(args[0].value), args[1].value.sVal)) + ast.newString(strutils.join( + toNimSeq(args[0].value), args[1].value.sVal)) template arraysDelete: untyped = delete(args[0].value.arrayItems, args[1].value.iVal) @@ -226,12 +234,12 @@ macro initStandardLibrary() = let fnArrays = @[ fwd("contains", ntLitBool, [(ntLitArray, "x"), (ntLitString, "item")], wrapper = getAst arraysContains()), - fwd("add", ntUnknown, [(ntLitArray, "x"), (ntLitString, "item")], wrapper = getAst arraysAdd()), - fwd("shift", ntUnknown, [(ntLitArray, "x")], wrapper = getAst arraysShift()), - fwd("pop", ntUnknown, [(ntLitArray, "x")], wrapper = getAst arraysPop()), - fwd("shuffle", ntUnknown, [(ntLitArray, "x")], wrapper = getAst arraysShuffle()), + fwd("add", ntLitVoid, [(ntLitArray, "x"), (ntLitString, "item")], wrapper = getAst arraysAdd()), + fwd("shift", ntLitVoid, [(ntLitArray, "x")], wrapper = getAst arraysShift()), + fwd("pop", ntLitVoid, [(ntLitArray, "x")], wrapper = getAst arraysPop()), + fwd("shuffle", ntLitVoid, [(ntLitArray, "x")], wrapper = getAst arraysShuffle()), fwd("join", ntLitString, [(ntLitArray, "x"), (ntLitString, "sep")], wrapper = getAst arraysJoin()), - fwd("delete", ntUnknown, [(ntLitArray, "x"), (ntLitInt, "pos")], wrapper = getAst arraysDelete()), + fwd("delete", ntLitVoid, [(ntLitArray, "x"), (ntLitInt, "pos")], wrapper = getAst arraysDelete()), fwd("find", ntLitInt, [(ntLitArray, "x"), (ntLitString, "item")], wrapper = getAst arraysFind()), ] # fnObjects = @[ @@ -260,7 +268,7 @@ macro initStandardLibrary() = # fwd("splitFile", ntTuple, [ntLitString]), fwd("extractFilename", ntLitString, [(ntLitString, "path")], "getFilename"), fwd("isAbsolute", ntLitBool, [(ntLitString, "path")]), - fwd("readFile", ntLitString, [(ntLitString, "path")], loadFrom="system"), + fwd("readFile", ntLitString, [(ntLitString, "path")], src="system"), fwd("isRelativeTo", ntLitBool, [(ntLitString, "path"), (ntLitString, "base")], "isRelative"), fwd("getCurrentDir", ntLitString), fwd("joinPath", ntLitString, [(ntLitString, "head"), (ntLitString, "tail")], "join"), @@ -276,7 +284,6 @@ macro initStandardLibrary() = ("sequtils", fnArrays, "arrays"), ("os", fnOs, "os") ] - echo "Generate Standard Library" for lib in libs: var sourceCode: string for fn in lib[1]: @@ -310,7 +317,7 @@ macro initStandardLibrary() = of ntLitFloat: "newFloat" of ntLitArray: "newArray" # todo implement toArray of ntLitObject: "newObject" # todo implement toObject - else: "" + else: "getVoidNode" var i = 0 var fnIdent = if fn.alias.len != 0: fn.alias else: fn.id add sourceCode, addFunction(fnIdent, fn.args, fn.returns) @@ -318,15 +325,15 @@ macro initStandardLibrary() = if not fn.hasWrapper: var callableNode = if lib[0] != "system": - if fn.loadFrom.len == 0: + if fn.src.len == 0: newCall(newDotExpr(ident(lib[0]), ident(fn.id))) else: - newCall(newDotExpr(ident(fn.loadFrom), ident(fn.id))) + newCall(newDotExpr(ident(fn.src), ident(fn.id))) else: - if fn.loadFrom.len == 0: + if fn.src.len == 0: newCall(newDotExpr(ident("system"), ident(fn.id))) else: - newCall(newDotExpr(ident(fn.loadFrom), ident(fn.id))) + newCall(newDotExpr(ident(fn.src), ident(fn.id))) for arg in fn.args: let fieldName = case arg[0] @@ -341,10 +348,7 @@ macro initStandardLibrary() = callableNode.add( newDotExpr( newDotExpr( - nnkBracketExpr.newTree( - ident("args"), - newLit(i) - ), + nnkBracketExpr.newTree(ident("args"), newLit(i)), ident("value") ), ident(fieldName) @@ -353,17 +357,20 @@ macro initStandardLibrary() = else: callableNode.add( newDotExpr( - nnkBracketExpr.newTree( - ident("args"), - newLit(i) - ), + nnkBracketExpr.newTree(ident"args", newLit(i)), ident("value") ), ) inc i - callNode = newCall(ident(valNode), callableNode) + if fn.returns != ntLitVoid: + callNode = newCall(ident(valNode), callableNode) + else: + callNode = nnkStmtList.newTree(callableNode, newCall(ident("getVoidNode"))) else: - callNode = fn.wrapper + if fn.returns != ntLitVoid: + callNode = fn.wrapper + else: + callNode = nnkStmtList.newTree(fn.wrapper, newCall(ident"getVoidNode")) lambda.add(newStmtList(callNode)) add result, newAssignment( @@ -384,11 +391,11 @@ macro initStandardLibrary() = newCall(ident("SourceCode"), newLit(sourceCode)) ) ) - when not defined release: - echo "std/" & lib[2] - echo sourceCode + # when not defined release: + # echo "std/" & lib[2] + # echo sourceCode -proc initstdlib*() = +proc initModuleSystem* = {.gcsafe.}: initStandardLibrary()