some progress on the VM
This commit is contained in:
parent
c260b22fbc
commit
e8fc470310
103 changed files with 294 additions and 11 deletions
151
compiler/main/nimbatch.nim
Normal file
151
compiler/main/nimbatch.nim
Normal file
|
|
@ -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())])
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue