tiny C backend for a much faster REPL

This commit is contained in:
Andreas Rumpf
2010-04-02 19:34:57 +02:00
parent 227b76c342
commit f530bbd631
12 changed files with 208 additions and 53 deletions

View File

@@ -17,7 +17,7 @@ elif defined(darwin):
lib = "gdk-x11-2.0"
else:
const
lib = "libgdk-x11-2.0.so"
lib = "libgdk-x11-2.0.so(|.0)"
const
NUMPTSTOBUFFER* = 200
MAX_TIMECOORD_AXES* = 128

118
lib/wrappers/tinyc.nim Normal file
View File

@@ -0,0 +1,118 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
type
TccState {.pure, final.} = object
PccState* = ptr TccState
TErrorFunc* = proc (opaque: pointer, msg: cstring) {.cdecl.}
proc openCCState*(): PccState {.importc: "tcc_new", cdecl.}
## create a new TCC compilation context
proc closeCCState*(s: PccState) {.importc: "tcc_delete", cdecl.}
## free a TCC compilation context
proc enableDebug*(s: PccState) {.importc: "tcc_enable_debug", cdecl.}
## add debug information in the generated code
proc setErrorFunc*(s: PccState, errorOpaque: pointer, errorFun: TErrorFunc) {.
cdecl, importc: "tcc_set_error_func".}
## set error/warning display callback
proc setWarning*(s: PccState, warningName: cstring, value: int) {.cdecl,
importc: "tcc_set_warning".}
## set/reset a warning
# preprocessor
proc addIncludePath*(s: PccState, pathname: cstring) {.cdecl,
importc: "tcc_add_include_path".}
## add include path
proc addSysincludePath*(s: PccState, pathname: cstring) {.cdecl,
importc: "tcc_add_sysinclude_path".}
## add in system include path
proc defineSymbol*(s: PccState, sym, value: cstring) {.cdecl,
importc: "tcc_define_symbol".}
## define preprocessor symbol 'sym'. Can put optional value
proc undefineSymbol*(s: PccState, sym: cstring) {.cdecl,
importc: "tcc_undefine_symbol".}
## undefine preprocess symbol 'sym'
# compiling
proc addFile*(s: PccState, filename: cstring): cint {.cdecl,
importc: "tcc_add_file".}
## add a file (either a C file, dll, an object, a library or an ld
## script). Return -1 if error.
proc compileString*(s: PccState, buf: cstring): cint {.cdecl,
importc: "tcc_compile_string".}
## compile a string containing a C source. Return non zero if error.
# linking commands
const
OutputMemory*: cint = 0 ## output will be ran in memory (no
## output file) (default)
OutputExe*: cint = 1 ## executable file
OutputDll*: cint = 2 ## dynamic library
OutputObj*: cint = 3 ## object file
OutputPreprocess*: cint = 4 ## preprocessed file (used internally)
OutputFormatElf*: cint = 0 ## default output format: ELF
OutputFormatBinary*: cint = 1 ## binary image output
OutputFormatCoff*: cint = 2 ## COFF
proc setOutputType*(s: PCCState, outputType: cint): cint {.cdecl,
importc: "tcc_set_output_type".}
## set output type. MUST BE CALLED before any compilation
proc addLibraryPath*(s: PccState, pathname: cstring): cint {.cdecl,
importc: "tcc_add_library_path".}
## equivalent to -Lpath option
proc addLibrary*(s: PCCState, libraryname: cstring): cint {.cdecl,
importc: "tcc_add_library".}
## the library name is the same as the argument of the '-l' option
proc addSymbol*(s: PccState, name: cstring, val: pointer): cint {.cdecl,
importc: "tcc_add_symbol".}
## add a symbol to the compiled program
proc outputFile*(s: PccState, filename: cstring): cint {.cdecl,
importc: "tcc_output_file".}
## output an executable, library or object file. DO NOT call
## tcc_relocate() before.
proc run*(s: PccState, argc: cint, argv: cstringArray): cint {.cdecl,
importc: "tcc_run".}
## link and run main() function and return its value. DO NOT call
## tcc_relocate() before.
proc relocate*(s: PccState, p: pointer): cint {.cdecl,
importc: "tcc_relocate".}
## copy code into memory passed in by the caller and do all relocations
## (needed before using tcc_get_symbol()).
## returns -1 on error and required size if ptr is NULL
proc getSymbol*(s: PccState, name: cstring): pointer {.cdecl,
importc: "tcc_get_symbol".}
## return symbol value or NULL if not found
proc setLibPath*(s: PccState, path: cstring) {.cdecl,
importc: "tcc_set_lib_path".}
## set CONFIG_TCCDIR at runtime

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -15,6 +15,9 @@ import
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, rnimsyn, treetab, cgmeth
when options.hasTinyCBackend:
import tccgen
proc cgenPass*(): TPass
# implementation
@@ -518,7 +521,8 @@ proc genProcAux(m: BModule, prc: PSym) =
if p.beforeRetNeeded: app(generatedProc, "BeforeRet: ;" & tnl)
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
appf(generatedProc, "profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
appf(generatedProc,
"profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
[toRope(prc.loc.a)])
app(generatedProc, returnStmt)
app(generatedProc, '}' & tnl)
@@ -600,13 +604,15 @@ proc genConstPrototype(m: BModule, sym: PSym) =
proc getFileHeader(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2009 Andreas Rumpf */$n", "; Generated by Nimrod Compiler v$1$n" &
"; (c) 2009 Andreas Rumpf$n", [toRope(versionAsString)])
"/* (c) 2010 Andreas Rumpf */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2010 Andreas Rumpf$n", [toRope(versionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2009 Andreas Rumpf */$n" & "/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n", "; Generated by Nimrod Compiler v$1$n" &
"; (c) 2009 Andreas Rumpf$n" & "; Compiled for: $2, $3, $4$n" &
"/* (c) 2010 Andreas Rumpf */$n" & "/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2010 Andreas Rumpf$n" & "; Compiled for: $2, $3, $4$n" &
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
@@ -668,7 +674,8 @@ proc genMainProc(m: BModule) =
" LPVOID lpvReserved) {$n" & " NimMain();$n" &
" return 1;$n" & "}$n"
WinNimDllMainLLVM = WinNimMainLLVM
WinCDllMainLLVM = "define stdcall i32 @DllMain(i32 %hinstDLL, i32 %fwdreason, $n" &
WinCDllMainLLVM =
"define stdcall i32 @DllMain(i32 %hinstDLL, i32 %fwdreason, $n" &
" i8* %lpvReserved) {$n" &
" call void @NimMain()$n" & " ret i32 1$n" & "}$n"
var nimMain, otherMain: TFormatStr
@@ -795,13 +802,13 @@ proc myOpen(module: PSym, filename: string): PPassContext =
if gNimDat == nil: registerTypeInfoModule()
result = newModule(module, filename)
proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext =
var cfile, cfilenoext, objFile: string
proc myOpenCached(module: PSym, filename: string,
rd: PRodReader): PPassContext =
if gNimDat == nil:
registerTypeInfoModule()
#MessageOut('cgen.myOpenCached has been called ' + filename);
cfile = changeFileExt(completeCFilePath(filename), cExt)
cfilenoext = changeFileExt(cfile, "")
var cfile = changeFileExt(completeCFilePath(filename), cExt)
var cfilenoext = changeFileExt(cfile, "")
addFileToLink(cfilenoext)
registerModuleToMain(module)
# XXX: this cannot be right here, initalization has to be appended during
@@ -838,18 +845,21 @@ proc finishModule(m: BModule) =
setlen(m.forwardedProcs, 0)
proc writeModule(m: BModule) =
var
cfile, cfilenoext: string
code: PRope
# generate code for the init statements of the module:
genInitCode(m)
finishTypeDescriptions(m)
cfile = completeCFilePath(m.cfilename)
cfilenoext = changeFileExt(cfile, "")
var cfile = completeCFilePath(m.cfilename)
var cfilenoext = changeFileExt(cfile, "")
if sfMainModule in m.module.flags:
# generate main file:
app(m.s[cfsProcHeaders], mainModProcs)
code = genModule(m, cfilenoext)
var code = genModule(m, cfilenoext)
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.compileCCode(ropeToStr(code))
return
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext):
addFileToCompile(cfilenoext)
addFileToLink(cfilenoext)
@@ -867,7 +877,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
finishModule(m)
if sfMainModule in m.module.flags:
var disp = generateMethodDispatchers()
for i in countup(0, sonsLen(disp) - 1): genProcAux(gNimDat, disp.sons[i].sym)
for i in 0..sonsLen(disp)-1: genProcAux(gNimDat, disp.sons[i].sym)
genMainProc(m)
# we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong

View File

@@ -36,6 +36,7 @@ Usage::
Command::
compile, c compile project with default code generator (C)
compileToC, cc compile project with C code generator
run compile the project in memory and run it
doc generate the documentation for inputfile
rst2html converts a reStructuredText file to HTML
rst2tex converts a reStructuredText file to TeX
@@ -70,7 +71,6 @@ Options:
AdvancedUsage = """
Advanced commands::
pas convert a Pascal file to Nimrod syntax
pretty pretty print the inputfile
genDepend generate a DOT file containing the
module dependency graph

View File

@@ -1014,9 +1014,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
case result.kind
of nkExceptBranch, nkReturnToken, nkBreakStmt: break
else: nil
of nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
nkIncludeStmt, nkImportStmt, nkFromStmt:
of nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma,
nkTypeSection, nkTemplateDef, nkConstSection, nkIteratorDef,
nkConverterDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
nil
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkLambda, nkContinueStmt, nkIdent:

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -480,8 +480,8 @@ proc genMappingFiles(list: TLinkedList): PRope =
it = PStrEntry(it.next)
proc writeMapping(gSymbolMapping: PRope) =
if not (optGenMapping in gGlobalOptions): return
var code = toRope("[C_Files]" & "\n")
if optGenMapping notin gGlobalOptions: return
var code = toRope("[C_Files]\n")
app(code, genMappingFiles(toCompile))
app(code, genMappingFiles(externalToCompile))
appf(code, "[Symbols]$n$1", [gSymbolMapping])

View File

@@ -118,7 +118,8 @@ proc CommandCompileToC(filename: string) =
registerPass(rodwrite.rodwritePass())
#registerPass(cleanupPass())
compileProject(filename)
extccomp.CallCCompiler(changeFileExt(filename, ""))
if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(filename, ""))
when has_LLVM_Backend:
proc CommandCompileToLLVM(filename: string) =
@@ -191,6 +192,13 @@ proc MainCommand(cmd, filename: string) =
gCmd = cmdCompileToC
wantFile(filename)
CommandCompileToC(filename)
of wRun:
gCmd = cmdRun
wantFile(filename)
when hasTinyCBackend:
CommandCompileToC(filename)
else:
rawMessage(errInvalidCommandX, cmd)
of wCompileToCpp:
gCmd = cmdCompileToCpp
wantFile(filename)
@@ -204,6 +212,8 @@ proc MainCommand(cmd, filename: string) =
wantFile(filename)
when has_LLVM_Backend:
CommandCompileToLLVM(filename)
else:
rawMessage(errInvalidCommandX, cmd)
of wPretty:
gCmd = cmdPretty
wantFile(filename) #CommandExportSymbols(filename);

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -298,14 +298,18 @@ const
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
TLineInfo*{.final.} = object # This is designed to be as small as possible, because it is used
# in syntax nodes. We safe space here by using two int16 and an int32
# on 64 bit and on 32 bit systems this is only 8 bytes.
TLineInfo*{.final.} = object # This is designed to be as small as possible,
# because it is used
# in syntax nodes. We safe space here by using
# two int16 and an int32
# on 64 bit and on 32 bit systems this is
# only 8 bytes.
line*, col*: int16
fileIndex*: int32
proc UnknownLineInfo*(): TLineInfo
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)}
gErrorCounter*: int = 0 # counts the number of errors

View File

@@ -11,6 +11,9 @@ import
times, commands, scanner, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt
when hasTinyCBackend:
import tccgen
var
arguments: string = "" # the arguments to be passed to the program that
# should be run
@@ -21,8 +24,7 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
while true:
parseopt.next(p)
case p.kind
of cmdEnd:
break
of cmdEnd: break
of cmdLongOption, cmdShortOption:
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here
@@ -41,7 +43,7 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
break
if pass == passCmd2:
arguments = cmdLineRest(p)
if not (optRun in gGlobalOptions) and (arguments != ""):
if optRun notin gGlobalOptions and arguments != "":
rawMessage(errArgsNeedRunOption, [])
proc HandleCmdLine() =
@@ -63,8 +65,11 @@ proc HandleCmdLine() =
ProcessCmdLine(passCmd2, command, filename)
MainCommand(command, filename)
if gVerbosity >= 2: echo(GC_getStatistics())
if (gCmd != cmdInterpret) and (msgs.gErrorCounter == 0):
rawMessage(hintSuccessX, [$(gLinesCompiled), $(getTime() - start)])
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.run()
if gCmd notin {cmdInterpret, cmdRun} and msgs.gErrorCounter == 0:
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)])
if optRun in gGlobalOptions:
when defined(unix):
var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))

View File

@@ -9,6 +9,9 @@
import
os, lists, strutils, nstrtabs
const
hasTinyCBackend* = true
type # please make sure we have under 32 options
# (improves code efficiency a lot!)
@@ -48,7 +51,8 @@ type # please make sure we have under 32 options
cmdDebugTrans, # debug a transformation pass
cmdRst2html, # convert a reStructuredText file to HTML
cmdRst2tex, # convert a reStructuredText file to TeX
cmdInteractive # start interactive session
cmdInteractive, # start interactive session
cmdRun # run the project via TCC backend
TStringSeq* = seq[string]
const

View File

@@ -67,10 +67,12 @@ const
type
TFormatStr* = string # later we may change it to CString for better
# performance of the code generator (assignments copy the format strings
# performance of the code generator (assignments
# copy the format strings
# though it is not necessary)
PRope* = ref TRope
TRope*{.acyclic.} = object of TObject # the empty rope is represented by nil to safe space
TRope*{.acyclic.} = object of TObject # the empty rope is represented
# by nil to safe space
left*, right*: PRope
length*: int
data*: string # != nil if a leaf
@@ -405,4 +407,4 @@ proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
else:
result = false
new(N) # init dummy node for splay algorithm
new(N) # init dummy node for splay algorithm

View File

@@ -1,20 +1,22 @@
#
#
# Nimrod REPL
# (c) Copyright 2010 Dominik Picheta
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import glib2, gtk2, gdk2, osproc, dialogs, strutils
type
output = tuple[compiler, app: string]
proc execCode(code: string): output =
proc execCode(code: string): string =
var f: TFile
if open(f, "temp.nim", fmWrite):
f.write(code)
f.close()
else:
raise newException(EIO, "Unable to open file")
var compilerOutput = osproc.execProcess("nimrod c temp.nim")
var appOutput = osproc.execProcess("temp.exe")
return (compilerOutput, appOutput)
raise newException(EIO, "Unable to open file")
result = osproc.execProcess("nimrod run --verbosity:0 temp.nim")
var shiftPressed = False
var w: gtk2.PWindow
@@ -83,8 +85,8 @@ proc inputKeyReleased(widget: PWidget, event: PEventKey,
try:
var r = execCode($InputText)
set_text(OutputTextBuffer, r[0] & r[1], len(r[0] & r[1]))
except:
set_text(OutputTextBuffer, r, len(r))
except EIO:
setError("Error: Could not open file temp.nim")