diff --git a/compiler/ast.nim b/compiler/ast/ast.nim similarity index 100% rename from compiler/ast.nim rename to compiler/ast/ast.nim diff --git a/compiler/astalgo.nim b/compiler/ast/astalgo.nim similarity index 100% rename from compiler/astalgo.nim rename to compiler/ast/astalgo.nim diff --git a/compiler/canonicalizer.nim b/compiler/ast/canonicalizer.nim similarity index 100% rename from compiler/canonicalizer.nim rename to compiler/ast/canonicalizer.nim diff --git a/compiler/trees.nim b/compiler/ast/trees.nim similarity index 100% rename from compiler/trees.nim rename to compiler/ast/trees.nim diff --git a/compiler/treetab.nim b/compiler/ast/treetab.nim similarity index 100% rename from compiler/treetab.nim rename to compiler/ast/treetab.nim diff --git a/compiler/types.nim b/compiler/ast/types.nim similarity index 100% rename from compiler/types.nim rename to compiler/ast/types.nim diff --git a/compiler/suggest.nim b/compiler/caas/suggest.nim similarity index 100% rename from compiler/suggest.nim rename to compiler/caas/suggest.nim diff --git a/compiler/ccgcalls.nim b/compiler/cgen/ccgcalls.nim similarity index 100% rename from compiler/ccgcalls.nim rename to compiler/cgen/ccgcalls.nim diff --git a/compiler/ccgexprs.nim b/compiler/cgen/ccgexprs.nim similarity index 100% rename from compiler/ccgexprs.nim rename to compiler/cgen/ccgexprs.nim diff --git a/compiler/ccgmerge.nim b/compiler/cgen/ccgmerge.nim similarity index 100% rename from compiler/ccgmerge.nim rename to compiler/cgen/ccgmerge.nim diff --git a/compiler/ccgstmts.nim b/compiler/cgen/ccgstmts.nim similarity index 100% rename from compiler/ccgstmts.nim rename to compiler/cgen/ccgstmts.nim diff --git a/compiler/ccgthreadvars.nim b/compiler/cgen/ccgthreadvars.nim similarity index 100% rename from compiler/ccgthreadvars.nim rename to compiler/cgen/ccgthreadvars.nim diff --git a/compiler/ccgtrav.nim b/compiler/cgen/ccgtrav.nim similarity index 100% rename from compiler/ccgtrav.nim rename to compiler/cgen/ccgtrav.nim diff --git a/compiler/ccgtypes.nim b/compiler/cgen/ccgtypes.nim similarity index 100% rename from compiler/ccgtypes.nim rename to compiler/cgen/ccgtypes.nim diff --git a/compiler/ccgutils.nim b/compiler/cgen/ccgutils.nim similarity index 100% rename from compiler/ccgutils.nim rename to compiler/cgen/ccgutils.nim diff --git a/compiler/cgen.nim b/compiler/cgen/cgen.nim similarity index 100% rename from compiler/cgen.nim rename to compiler/cgen/cgen.nim diff --git a/compiler/cgendata.nim b/compiler/cgen/cgendata.nim similarity index 100% rename from compiler/cgendata.nim rename to compiler/cgen/cgendata.nim diff --git a/compiler/extccomp.nim b/compiler/cgen/extccomp.nim similarity index 100% rename from compiler/extccomp.nim rename to compiler/cgen/extccomp.nim diff --git a/compiler/tccgen.nim b/compiler/cgen/tccgen.nim similarity index 100% rename from compiler/tccgen.nim rename to compiler/cgen/tccgen.nim diff --git a/compiler/bitsets.nim b/compiler/common/bitsets.nim similarity index 100% rename from compiler/bitsets.nim rename to compiler/common/bitsets.nim diff --git a/compiler/crc.nim b/compiler/common/crc.nim similarity index 100% rename from compiler/crc.nim rename to compiler/common/crc.nim diff --git a/compiler/lists.nim b/compiler/common/lists.nim similarity index 100% rename from compiler/lists.nim rename to compiler/common/lists.nim diff --git a/compiler/llstream.nim b/compiler/common/llstream.nim similarity index 100% rename from compiler/llstream.nim rename to compiler/common/llstream.nim diff --git a/compiler/ropes.nim b/compiler/common/ropes.nim similarity index 100% rename from compiler/ropes.nim rename to compiler/common/ropes.nim diff --git a/compiler/saturate.nim b/compiler/common/saturate.nim similarity index 100% rename from compiler/saturate.nim rename to compiler/common/saturate.nim diff --git a/compiler/testability.nim b/compiler/common/testability.nim similarity index 100% rename from compiler/testability.nim rename to compiler/common/testability.nim diff --git a/compiler/docgen.nim b/compiler/docgen/docgen.nim similarity index 100% rename from compiler/docgen.nim rename to compiler/docgen/docgen.nim diff --git a/compiler/docgen2.nim b/compiler/docgen/docgen2.nim similarity index 100% rename from compiler/docgen2.nim rename to compiler/docgen/docgen2.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen/jsgen.nim similarity index 100% rename from compiler/jsgen.nim rename to compiler/jsgen/jsgen.nim diff --git a/compiler/jstypes.nim b/compiler/jsgen/jstypes.nim similarity index 100% rename from compiler/jstypes.nim rename to compiler/jsgen/jstypes.nim diff --git a/compiler/idents.nim b/compiler/keywords/idents.nim similarity index 100% rename from compiler/idents.nim rename to compiler/keywords/idents.nim diff --git a/compiler/wordrecg.nim b/compiler/keywords/wordrecg.nim similarity index 100% rename from compiler/wordrecg.nim rename to compiler/keywords/wordrecg.nim diff --git a/compiler/lexer.nim b/compiler/lexer/lexer.nim similarity index 100% rename from compiler/lexer.nim rename to compiler/lexer/lexer.nim diff --git a/compiler/nimlexbase.nim b/compiler/lexer/nimlexbase.nim similarity index 100% rename from compiler/nimlexbase.nim rename to compiler/lexer/nimlexbase.nim diff --git a/compiler/importer.nim b/compiler/main/importer.nim similarity index 100% rename from compiler/importer.nim rename to compiler/main/importer.nim diff --git a/compiler/main.nim b/compiler/main/main.nim similarity index 100% rename from compiler/main.nim rename to compiler/main/main.nim diff --git a/compiler/modules.nim b/compiler/main/modules.nim similarity index 100% rename from compiler/modules.nim rename to compiler/main/modules.nim diff --git a/compiler/main/nimbatch.nim b/compiler/main/nimbatch.nim new file mode 100644 index 000000000..7ca207d88 --- /dev/null +++ b/compiler/main/nimbatch.nim @@ -0,0 +1,151 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This file implements the new "batch compiler" that can translate Nimrod +# code into POSIX shell scripts or Windows ``.bat`` files. Only a small +# subset of Nimrod can be translated. This compiler also acts as a new +# "hacking the Nimrod compiler" tutorial. + + +## ============================== +## Let's hack the Nimrod compiler +## ============================== + +## Starting with version 0.9.6 the compiler's internals have been cleaned up +## quite a bit. However, still lot's of weird modules need to be imported +## before we can start: + +import + llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, + os, condsyms, rodread, rodwrite, times, + wordrecg, sem, semdata, idents, passes, docgen, extccomp, + cgen, jsgen, json, nversion, + platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, + tables, docgen2, service, parser, modules + +proc `=~`(s: PSym; name: string): bool = + let a = name.split('.') + var s = s + for i in countdown(a.high, a.low): + if s == nil or not identEq(s.name, a[i]): return false + s = s.owner + return true + +type + ShellTarget = enum + targetBatch, targetSh + Context = ref object + target: ShellTarget + code: string + +proc `=~`(n: PNode; name: string): bool = + result = n.kind == nkSym and match(n.sym, name) + +proc gen(c: Context; n: PNode) = + template `~`(x): expr = op =~ x + template `|`(a, b): expr = (if c.target == targetBatch: a else: b) + template add(x) = c.code.add(x) + template addf(x, y) = c.code.addf(x, y) + + case n.kind + of nkIfStmt, nkIfExpr: + + of nkForStmt: + + of nkCallKinds: + let op = n[0] + if ~"stdlib.os.changeDir": + addf("" | "", + elif ~"stdlib.os.createDir": + addf("mkdir $#", + +proc semanticPasses() = + registerPass verbosePass + registerPass semPass + +proc commandCompileToSH = + #incl(gGlobalOptions, optSafeCode) + setTarget(osJS, cpuJS) + #initDefines() + defineSymbol("nimrod") # 'nimrod' is always defined + defineSymbol("batch") + semanticPasses() + registerPass(JSgenPass) + compileProject() + +proc wantMainModule = + if gProjectFull.len == 0: + if optMainModule.len == 0: + fatal(gCmdLineInfo, errCommandExpectsFilename) + else: + gProjectName = optMainModule + gProjectFull = gProjectPath / gProjectName + + gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx + +proc requireMainModuleOption = + if optMainModule.len == 0: + fatal(gCmdLineInfo, errMainModuleMustBeSpecified) + else: + gProjectName = optMainModule + gProjectFull = gProjectPath / gProjectName + + gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx + +proc mainCommand* = + # In "nimrod serve" scenario, each command must reset the registered passes + clearPasses() + gLastCmdTime = epochTime() + appendStr(searchPaths, options.libpath) + if gProjectFull.len != 0: + # current path is always looked first for modules + prependStr(searchPaths, gProjectPath) + setId(100) + passes.gIncludeFile = includeModule + passes.gImportModule = importModule + case command.normalize + of "c", "cc", "compile", "compiletoc": + # compile means compileToC currently + gCmd = cmdCompileToC + wantMainModule() + commandCompileToC() + of "cpp", "compiletocpp": + extccomp.cExt = ".cpp" + gCmd = cmdCompileToCpp + if cCompiler == ccGcc: setCC("gcc") + wantMainModule() + defineSymbol("cpp") + commandCompileToC() + of "objc", "compiletooc": + extccomp.cExt = ".m" + gCmd = cmdCompileToOC + wantMainModule() + defineSymbol("objc") + commandCompileToC() + of "run": + gCmd = cmdRun + wantMainModule() + when hasTinyCBackend: + extccomp.setCC("tcc") + commandCompileToC() + else: + rawMessage(errInvalidCommandX, command) + of "js", "compiletojs": + gCmd = cmdCompileToJS + wantMainModule() + commandCompileToJS() + else: + rawMessage(errInvalidCommandX, command) + + if (msgs.gErrorCounter == 0 and + gCmd notin {cmdInterpret, cmdRun, cmdDump} and + gVerbosity > 0): + rawMessage(hintSuccessX, [$gLinesCompiled, + formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), + formatSize(getTotalMem())]) diff --git a/compiler/nimeval.nim b/compiler/main/nimeval.nim similarity index 100% rename from compiler/nimeval.nim rename to compiler/main/nimeval.nim diff --git a/compiler/pretty.nim b/compiler/main/pretty.nim similarity index 100% rename from compiler/pretty.nim rename to compiler/main/pretty.nim diff --git a/compiler/service.nim b/compiler/main/service.nim similarity index 100% rename from compiler/service.nim rename to compiler/main/service.nim diff --git a/compiler/nimrod.nimrod.cfg b/compiler/nimrod.nimrod.cfg index 2c6e6f249..ab1cc9f73 100644 --- a/compiler/nimrod.nimrod.cfg +++ b/compiler/nimrod.nimrod.cfg @@ -5,7 +5,25 @@ mainModule:"nimrod.nim" # gc:markAndSweep hint[XDeclaredButNotUsed]:off -path:"llvm" +path:"ast" +path:"caas" +path:"cgen" +path:"common" +path:"docgen" +path:"jsgen" +path:"keywords" +path:"lexer" +path:"main" +path:"options" +path:"parsers" +path:"passes" +path:"renderers" +path:"rodfiles" +path:"sem" +path:"symtab" +path:"transformations" +path:"vm" + path:"$projectPath/.." path:"$lib/packages/docutils" diff --git a/compiler/babelcmd.nim b/compiler/options/babelcmd.nim similarity index 100% rename from compiler/babelcmd.nim rename to compiler/options/babelcmd.nim diff --git a/compiler/commands.nim b/compiler/options/commands.nim similarity index 100% rename from compiler/commands.nim rename to compiler/options/commands.nim diff --git a/compiler/condsyms.nim b/compiler/options/condsyms.nim similarity index 100% rename from compiler/condsyms.nim rename to compiler/options/condsyms.nim diff --git a/compiler/msgs.nim b/compiler/options/msgs.nim similarity index 100% rename from compiler/msgs.nim rename to compiler/options/msgs.nim diff --git a/compiler/nversion.nim b/compiler/options/nversion.nim similarity index 100% rename from compiler/nversion.nim rename to compiler/options/nversion.nim diff --git a/compiler/options.nim b/compiler/options/options.nim similarity index 99% rename from compiler/options.nim rename to compiler/options/options.nim index 58a340d21..14946823b 100644 --- a/compiler/options.nim +++ b/compiler/options/options.nim @@ -277,8 +277,7 @@ when noTimeMachine: ## ## The whole proc is optional and will ignore all kinds of errors. The only ## way to be sure that it works is to call ``tmutil isexcluded path``. - if alreadyExcludedDirs.contains(dir): return - alreadyExcludedDirs.incl(dir) + if alreadyExcludedDirs.containsOrIncl(dir): return try: var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir]) discard p.waitForExit diff --git a/compiler/platform.nim b/compiler/options/platform.nim similarity index 100% rename from compiler/platform.nim rename to compiler/options/platform.nim diff --git a/compiler/filter_tmpl.nim b/compiler/parsers/filter_tmpl.nim similarity index 100% rename from compiler/filter_tmpl.nim rename to compiler/parsers/filter_tmpl.nim diff --git a/compiler/filters.nim b/compiler/parsers/filters.nim similarity index 100% rename from compiler/filters.nim rename to compiler/parsers/filters.nim diff --git a/compiler/nimconf.nim b/compiler/parsers/nimconf.nim similarity index 100% rename from compiler/nimconf.nim rename to compiler/parsers/nimconf.nim diff --git a/compiler/parser.nim b/compiler/parsers/parser.nim similarity index 100% rename from compiler/parser.nim rename to compiler/parsers/parser.nim diff --git a/compiler/pbraces.nim b/compiler/parsers/pbraces.nim similarity index 100% rename from compiler/pbraces.nim rename to compiler/parsers/pbraces.nim diff --git a/compiler/syntaxes.nim b/compiler/parsers/syntaxes.nim similarity index 100% rename from compiler/syntaxes.nim rename to compiler/parsers/syntaxes.nim diff --git a/compiler/depends.nim b/compiler/passes/depends.nim similarity index 100% rename from compiler/depends.nim rename to compiler/passes/depends.nim diff --git a/compiler/passaux.nim b/compiler/passes/passaux.nim similarity index 100% rename from compiler/passaux.nim rename to compiler/passes/passaux.nim diff --git a/compiler/passes.nim b/compiler/passes/passes.nim similarity index 100% rename from compiler/passes.nim rename to compiler/passes/passes.nim diff --git a/compiler/renderer.nim b/compiler/renderers/renderer.nim similarity index 100% rename from compiler/renderer.nim rename to compiler/renderers/renderer.nim diff --git a/compiler/typesrenderer.nim b/compiler/renderers/typesrenderer.nim similarity index 100% rename from compiler/typesrenderer.nim rename to compiler/renderers/typesrenderer.nim diff --git a/compiler/idgen.nim b/compiler/rodfiles/idgen.nim similarity index 100% rename from compiler/idgen.nim rename to compiler/rodfiles/idgen.nim diff --git a/compiler/rodread.nim b/compiler/rodfiles/rodread.nim similarity index 100% rename from compiler/rodread.nim rename to compiler/rodfiles/rodread.nim diff --git a/compiler/rodutils.nim b/compiler/rodfiles/rodutils.nim similarity index 100% rename from compiler/rodutils.nim rename to compiler/rodfiles/rodutils.nim diff --git a/compiler/rodwrite.nim b/compiler/rodfiles/rodwrite.nim similarity index 100% rename from compiler/rodwrite.nim rename to compiler/rodfiles/rodwrite.nim diff --git a/compiler/aliases.nim b/compiler/sem/aliases.nim similarity index 100% rename from compiler/aliases.nim rename to compiler/sem/aliases.nim diff --git a/compiler/evaltempl.nim b/compiler/sem/evaltempl.nim similarity index 100% rename from compiler/evaltempl.nim rename to compiler/sem/evaltempl.nim diff --git a/compiler/guards.nim b/compiler/sem/guards.nim similarity index 100% rename from compiler/guards.nim rename to compiler/sem/guards.nim diff --git a/compiler/hlo.nim b/compiler/sem/hlo.nim similarity index 100% rename from compiler/hlo.nim rename to compiler/sem/hlo.nim diff --git a/compiler/nimsets.nim b/compiler/sem/nimsets.nim similarity index 100% rename from compiler/nimsets.nim rename to compiler/sem/nimsets.nim diff --git a/compiler/parampatterns.nim b/compiler/sem/parampatterns.nim similarity index 100% rename from compiler/parampatterns.nim rename to compiler/sem/parampatterns.nim diff --git a/compiler/patterns.nim b/compiler/sem/patterns.nim similarity index 100% rename from compiler/patterns.nim rename to compiler/sem/patterns.nim diff --git a/compiler/pragmas.nim b/compiler/sem/pragmas.nim similarity index 100% rename from compiler/pragmas.nim rename to compiler/sem/pragmas.nim diff --git a/compiler/procfind.nim b/compiler/sem/procfind.nim similarity index 100% rename from compiler/procfind.nim rename to compiler/sem/procfind.nim diff --git a/compiler/sem.nim b/compiler/sem/sem.nim similarity index 100% rename from compiler/sem.nim rename to compiler/sem/sem.nim diff --git a/compiler/semcall.nim b/compiler/sem/semcall.nim similarity index 100% rename from compiler/semcall.nim rename to compiler/sem/semcall.nim diff --git a/compiler/semdata.nim b/compiler/sem/semdata.nim similarity index 100% rename from compiler/semdata.nim rename to compiler/sem/semdata.nim diff --git a/compiler/semdestruct.nim b/compiler/sem/semdestruct.nim similarity index 100% rename from compiler/semdestruct.nim rename to compiler/sem/semdestruct.nim diff --git a/compiler/semexprs.nim b/compiler/sem/semexprs.nim similarity index 100% rename from compiler/semexprs.nim rename to compiler/sem/semexprs.nim diff --git a/compiler/semfold.nim b/compiler/sem/semfold.nim similarity index 100% rename from compiler/semfold.nim rename to compiler/sem/semfold.nim diff --git a/compiler/semgnrc.nim b/compiler/sem/semgnrc.nim similarity index 100% rename from compiler/semgnrc.nim rename to compiler/sem/semgnrc.nim diff --git a/compiler/seminst.nim b/compiler/sem/seminst.nim similarity index 100% rename from compiler/seminst.nim rename to compiler/sem/seminst.nim diff --git a/compiler/semmacrosanity.nim b/compiler/sem/semmacrosanity.nim similarity index 100% rename from compiler/semmacrosanity.nim rename to compiler/sem/semmacrosanity.nim diff --git a/compiler/semmagic.nim b/compiler/sem/semmagic.nim similarity index 100% rename from compiler/semmagic.nim rename to compiler/sem/semmagic.nim diff --git a/compiler/semparallel.nim b/compiler/sem/semparallel.nim similarity index 100% rename from compiler/semparallel.nim rename to compiler/sem/semparallel.nim diff --git a/compiler/sempass2.nim b/compiler/sem/sempass2.nim similarity index 100% rename from compiler/sempass2.nim rename to compiler/sem/sempass2.nim diff --git a/compiler/semstmts.nim b/compiler/sem/semstmts.nim similarity index 100% rename from compiler/semstmts.nim rename to compiler/sem/semstmts.nim diff --git a/compiler/semtempl.nim b/compiler/sem/semtempl.nim similarity index 100% rename from compiler/semtempl.nim rename to compiler/sem/semtempl.nim diff --git a/compiler/semtypes.nim b/compiler/sem/semtypes.nim similarity index 100% rename from compiler/semtypes.nim rename to compiler/sem/semtypes.nim diff --git a/compiler/semtypinst.nim b/compiler/sem/semtypinst.nim similarity index 100% rename from compiler/semtypinst.nim rename to compiler/sem/semtypinst.nim diff --git a/compiler/sigmatch.nim b/compiler/sem/sigmatch.nim similarity index 100% rename from compiler/sigmatch.nim rename to compiler/sem/sigmatch.nim diff --git a/compiler/lookups.nim b/compiler/symtab/lookups.nim similarity index 100% rename from compiler/lookups.nim rename to compiler/symtab/lookups.nim diff --git a/compiler/magicsys.nim b/compiler/symtab/magicsys.nim similarity index 100% rename from compiler/magicsys.nim rename to compiler/symtab/magicsys.nim diff --git a/compiler/cgmeth.nim b/compiler/transformations/cgmeth.nim similarity index 100% rename from compiler/cgmeth.nim rename to compiler/transformations/cgmeth.nim diff --git a/compiler/lambdalifting.nim b/compiler/transformations/lambdalifting.nim similarity index 100% rename from compiler/lambdalifting.nim rename to compiler/transformations/lambdalifting.nim diff --git a/compiler/lowerings.nim b/compiler/transformations/lowerings.nim similarity index 100% rename from compiler/lowerings.nim rename to compiler/transformations/lowerings.nim diff --git a/compiler/transf.nim b/compiler/transformations/transf.nim similarity index 100% rename from compiler/transf.nim rename to compiler/transformations/transf.nim diff --git a/compiler/evalffi.nim b/compiler/vm/evalffi.nim similarity index 100% rename from compiler/evalffi.nim rename to compiler/vm/evalffi.nim diff --git a/compiler/vm.nim b/compiler/vm/vm.nim similarity index 96% rename from compiler/vm.nim rename to compiler/vm/vm.nim index 66595856a..d1204b7ec 100644 --- a/compiler/vm.nim +++ b/compiler/vm/vm.nim @@ -44,6 +44,7 @@ type # parameters come first next: PStackFrame # for stacking comesFrom: int + firstArg, argsLen, resultPos: Byte # used when frame is passed to callback safePoints: seq[int] # used for exception handling # XXX 'break' should perform cleanup actions # What does the C backend do for it? @@ -141,6 +142,51 @@ template createStr(x) = template createSet(x) = x.node = newNode(nkCurly) +proc argsLen*(f: VmFrame): Natural = + ## returns the number of arguments that this frame contains. Normally you + ## should already know this number due to nimrod's static typing. + result = Natural(cast[PStackFrame](f).argsLen) + +proc getInt*(f: VmFrame; index: Natural): BiggestInt = + ## returns the value of the index'th slot in the frame. The slot has to be + ## of the type: int|int16|... + let f = cast[PStackFrame](f) + result = f.slots[index + f.firstArg].intVal + +proc getFloat*(f: VmFrame; index: Natural): BiggestFloat = + ## returns the value of the index'th slot in the frame. The slot has to be + ## of the type: float|float32|float64 or a distinct type of float or a + ## float range. + let f = cast[PStackFrame](f) + result = f.slots[index + f.firstArg].floatVal + +proc getString*(f: VmFrame; index: Natural): string = + ## returns the value of the index'th slot in the frame. The slot has to be + ## of the type string. + let f = cast[PStackFrame](f) + result = f.slots[index + f.firstArg].n.strVal + +template rawSetResult(a, k, field) {.immediate, dirty.} = + if a.kind != k: + myreset a + a.kind = k + a.field = x + +proc setResultInt*(f: VmFrame; x: BiggestInt) = + ## sets the result value of the wrapped proc. + let f = cast[PStackFrame](f) + rawSetResult(f.slots[f.firstArg-1], rkInt, intVal) + +proc setResultFloat*(f: VmFrame; x: BiggestFloat) = + ## sets the result value of the wrapped proc. + let f = cast[PStackFrame](f) + rawSetResult(f.slots[f.firstArg-1], rkFloat, floatVal) + +proc setResultString*(f: VmFrame; x: string) = + ## sets the result value of the wrapped proc. + let f = cast[PStackFrame](f) + rawSetResult(f.slots[f.firstArg-1], rkStr, n.strVal) + proc moveConst(x: var TFullReg, y: TFullReg) = if x.kind != y.kind: myreset(x) @@ -791,7 +837,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let bb = regs[rb].node let isClosure = bb.kind == nkPar let prc = if not isClosure: bb.sym else: bb.sons[0].sym - if sfImportc in prc.flags: + if prc.offset < 0: + tos.firstArg = rb + tos.argsLen = rc + tos.resultPos = ra + c.vmProcs[-prc.offset - 1].prc(tos) + elif sfImportc in prc.flags: if allowFFI notin c.features: globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") # we pass 'tos.slots' instead of 'regs' so that the compiler can keep diff --git a/compiler/vmdef.nim b/compiler/vm/vmdef.nim similarity index 96% rename from compiler/vmdef.nim rename to compiler/vm/vmdef.nim index c391d8415..afd723feb 100644 --- a/compiler/vmdef.nim +++ b/compiler/vm/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, intsets +import ast, passes, msgs, intsets, strtabs const byteExcess* = 128 # we use excess-K for immediates @@ -170,7 +170,13 @@ type sym*: PSym slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] maxSlots*: int - + + VmFrame* = distinct pointer + VmProc* = proc (f: VmFrame) {.closure.} + + VmSym* = object + name*: string + prc*: VmProc PCtx* = ref TCtx TCtx* = object of passes.TPassContext # code gen context code*: seq[TInstr] @@ -188,6 +194,8 @@ type features*: TSandboxFlags traceActive*: bool loopIterations*: int + vmProcs*: seq[VmSym] + marked*: PStringTable TPosition* = distinct int @@ -196,7 +204,8 @@ type proc newCtx*(module: PSym): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], - prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations) + prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, + vmProcs: @[], marked: nil) proc refresh*(c: PCtx, module: PSym) = c.module = module diff --git a/compiler/vmdeps.nim b/compiler/vm/vmdeps.nim similarity index 100% rename from compiler/vmdeps.nim rename to compiler/vm/vmdeps.nim diff --git a/compiler/vmgen.nim b/compiler/vm/vmgen.nim similarity index 98% rename from compiler/vmgen.nim rename to compiler/vm/vmgen.nim index c1ec637dd..647daff0a 100644 --- a/compiler/vmgen.nim +++ b/compiler/vm/vmgen.nim @@ -29,7 +29,7 @@ import unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, - trees, intsets, rodread, magicsys, options, lowerings + trees, intsets, rodread, magicsys, options, lowerings, strtabs, idents from os import splitFile @@ -1470,6 +1470,28 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) = proc genProc*(c: PCtx; s: PSym): int +proc `=~`(s: PSym; name: string): bool = + let a = name.split('.') + var s = s + for i in countdown(a.high, a.low): + if s == nil or not identEq(s.name, a[i]): return false + s = s.owner + return true + +proc getVmProcSlot(c: PCtx; s: PSym): int = + for i in 0..high(c.vmProcs): + if s =~ c.vmProcs[i].name: return i + result = -1 + +proc registerProc*(c: PCtx; name: string; procedure: VmProc) = + ## provides an implementation for a proc that is preferred over the proc's + ## body. This is used to provide operations that otherwise would require FFI + ## support. + c.vmProcs.add VmSym(name: name, prc: procedure) + if c.marked == nil: c.marked = newStringTable(modeStyleInsensitive) + let a = name.split('.') + c.marked[a[a.high]] = "" + proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = case n.kind of nkSym: @@ -1481,6 +1503,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators: # 'skTemplate' is only allowed for 'getAst' support: if sfImportc in s.flags: c.importcSym(n.info, s) + if c.marked != nil and c.marked.hasKey(s.name.s) and s.offset == 0: + let idx = getVmProcSlot(c, s) + if idx >= 0: s.offset = -idx-1 genLit(c, n, dest) of skConst: gen(c, s.ast, dest) diff --git a/compiler/vm/vmhooks.nim b/compiler/vm/vmhooks.nim new file mode 100644 index 000000000..3d0e1759b --- /dev/null +++ b/compiler/vm/vmhooks.nim @@ -0,0 +1,31 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements extension hooks for the VM. + +import vmdef + +type + VmFrame* = object ## a frame object provides the interface between native + ## procs and interpreted procs. + sf: PStackFrame # real underlying stack frame + firstArg: int # firstArg-1 is the position where + # the result has to be stored + +proc readLineWrapper(f: VmFrame) = + let file = cast[TFile](f.getInt 0) + f.setResultString file.readLine() + +proc registerProc*(c: VmContext; fullname: string; procedure: VmCallback) = + let c = PCtx(c) + let comps = fullname.split('.') + # put the last component of the name into c.marker to speed up lookups: + +vm.registerProc "stdlib.system.readLine", readLineWrapper + diff --git a/doc/spawn.txt b/doc/spawn.txt index ed500f3a5..790602234 100644 --- a/doc/spawn.txt +++ b/doc/spawn.txt @@ -93,6 +93,5 @@ variables at the same time: Like the ``parallel`` statement data flow variables ensure that no data races are possible. Due to technical limitations not every type ``T`` is possible in a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` -or of a type that doesn't contain a type that is garbage collected. This -restriction will be removed in the future. - +or of a type that doesn't contain a type that describes garbage collected +memory. This restriction may be removed in the future.