mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 02:42:05 +00:00
Merge branch 'master' of https://github.com/Araq/Nimrod into vm2
Conflicts: web/news.txt
This commit is contained in:
397
.gitignore
vendored
397
.gitignore
vendored
@@ -63,7 +63,10 @@ examples/cross_calculator/android/tags
|
||||
/examples/allany
|
||||
/examples/cairoex
|
||||
/examples/cgiex
|
||||
/examples/cgi/cgi_stacktrace
|
||||
/examples/cgi/example
|
||||
/examples/curlex
|
||||
/examples/debugging
|
||||
/examples/docstrings
|
||||
/examples/filterex
|
||||
/examples/fizzbuzz
|
||||
@@ -89,6 +92,12 @@ examples/cross_calculator/android/tags
|
||||
/examples/pythonex
|
||||
/examples/sdlex
|
||||
/examples/statcsv
|
||||
/examples/talk/dsl
|
||||
/examples/talk/formatoptimizer
|
||||
/examples/talk/hoisting
|
||||
/examples/talk/lazyeval
|
||||
/examples/talk/quasiquote
|
||||
/examples/talk/tags
|
||||
/examples/tclex
|
||||
/examples/transff
|
||||
/examples/tunit
|
||||
@@ -96,10 +105,13 @@ examples/cross_calculator/android/tags
|
||||
/examples/x11ex
|
||||
/lib/libnimrtl.dylib
|
||||
/lib/libserver.dylib
|
||||
/lib/packages/docutils/highlite
|
||||
/lib/pure/actors
|
||||
/lib/pure/algorithm
|
||||
/lib/pure/asyncio
|
||||
/lib/pure/base64
|
||||
/lib/pure/basic2d
|
||||
/lib/pure/basic3d
|
||||
/lib/pure/browsers
|
||||
/lib/pure/cgi
|
||||
/lib/pure/collections/sequtils
|
||||
@@ -111,6 +123,7 @@ examples/cross_calculator/android/tags
|
||||
/lib/pure/encodings
|
||||
/lib/pure/endians
|
||||
/lib/pure/events
|
||||
/lib/pure/fsmonitor
|
||||
/lib/pure/ftpclient
|
||||
/lib/pure/gentabs
|
||||
/lib/pure/hashes
|
||||
@@ -127,19 +140,23 @@ examples/cross_calculator/android/tags
|
||||
/lib/pure/math
|
||||
/lib/pure/md5
|
||||
/lib/pure/memfiles
|
||||
/lib/pure/mersenne
|
||||
/lib/pure/mimetypes
|
||||
/lib/pure/nimprof
|
||||
/lib/pure/numeric
|
||||
/lib/pure/oids
|
||||
/lib/pure/os
|
||||
/lib/pure/osproc
|
||||
/lib/pure/parsecfg
|
||||
/lib/pure/parsecsv
|
||||
/lib/pure/parseopt
|
||||
/lib/pure/parseopt2
|
||||
/lib/pure/parsesql
|
||||
/lib/pure/parseurl
|
||||
/lib/pure/parseutils
|
||||
/lib/pure/parsexml
|
||||
/lib/pure/pegs
|
||||
/lib/pure/poly
|
||||
/lib/pure/redis
|
||||
/lib/pure/romans
|
||||
/lib/pure/ropes
|
||||
@@ -167,9 +184,9 @@ examples/cross_calculator/android/tags
|
||||
/run.json
|
||||
/testresults.html
|
||||
/testresults.json
|
||||
/tests/caas/SymbolProcRun.*/
|
||||
/tests/caas/absurd_nesting
|
||||
/tests/caas/completion_dot_syntax_main
|
||||
/tests/caasdriver
|
||||
/tests/caas/forward_declarations
|
||||
/tests/caas/idetools_api
|
||||
/tests/caas/imported
|
||||
@@ -178,6 +195,380 @@ examples/cross_calculator/android/tags
|
||||
/tests/caas/issue_477_dynamic_dispatch
|
||||
/tests/caas/its_full_of_procs
|
||||
/tests/caas/main
|
||||
/tests/caasdriver
|
||||
/tools/nimgrep
|
||||
/tests/caas/SymbolProcRun.*/
|
||||
/tests/ccg/tmissingbracket
|
||||
/tests/compile/talias
|
||||
/tests/compile/tambsym2
|
||||
/tests/compile/tarrindx
|
||||
/tests/compile/tassign
|
||||
/tests/compile/tbindoverload
|
||||
/tests/compile/tcan_alias_generic
|
||||
/tests/compile/tcan_alias_specialised_generic
|
||||
/tests/compile/tcan_inherit_generic
|
||||
/tests/compile/tcan_specialise_generic
|
||||
/tests/compile/tccgen1
|
||||
/tests/compile/tclosure4
|
||||
/tests/compile/tclosurebug2
|
||||
/tests/compile/tcmdline
|
||||
/tests/compile/tcodegenbug1
|
||||
/tests/compile/tcolonisproc
|
||||
/tests/compile/tcolors
|
||||
/tests/compile/tcommontype
|
||||
/tests/compile/tcompiles
|
||||
/tests/compile/tcomputedgoto
|
||||
/tests/compile/tconsteval
|
||||
/tests/compile/tconstraints
|
||||
/tests/compile/tconvcolors
|
||||
/tests/compile/tcputime
|
||||
/tests/compile/tdefaultprocparam
|
||||
/tests/compile/tdictdestruct
|
||||
/tests/compile/tdiscardable
|
||||
/tests/compile/tdllvar
|
||||
/tests/compile/tdumpast
|
||||
/tests/compile/tdumpast2
|
||||
/tests/compile/techo
|
||||
/tests/compile/teffects1
|
||||
/tests/compile/temptyecho
|
||||
/tests/compile/tendian
|
||||
/tests/compile/tenum
|
||||
/tests/compile/tenum2
|
||||
/tests/compile/tenum3
|
||||
/tests/compile/teval1
|
||||
/tests/compile/texport
|
||||
/tests/compile/tfib
|
||||
/tests/compile/tforwardgeneric
|
||||
/tests/compile/tforwty
|
||||
/tests/compile/tforwty2
|
||||
/tests/compile/tgeneric
|
||||
/tests/compile/tgeneric2
|
||||
/tests/compile/tgeneric3
|
||||
/tests/compile/tgeneric4
|
||||
/tests/compile/tgenericmatcher
|
||||
/tests/compile/tgenericmatcher2
|
||||
/tests/compile/tgenericprocvar
|
||||
/tests/compile/tgenericprop
|
||||
/tests/compile/tgenericrefs
|
||||
/tests/compile/tgenerictmpl
|
||||
/tests/compile/tgenericvariant
|
||||
/tests/compile/tgensymgeneric
|
||||
/tests/compile/tgetstartmilsecs
|
||||
/tests/compile/tglobalforvar
|
||||
/tests/compile/thallo
|
||||
/tests/compile/theaproots
|
||||
/tests/compile/thexrange
|
||||
/tests/compile/thygienictempl
|
||||
/tests/compile/tident
|
||||
/tests/compile/timplicititems
|
||||
/tests/compile/timplictderef
|
||||
/tests/compile/tinheritref
|
||||
/tests/compile/tio
|
||||
/tests/compile/tircbot
|
||||
/tests/compile/titer
|
||||
/tests/compile/titer2
|
||||
/tests/compile/titer_no_tuple_unpack
|
||||
/tests/compile/titerovl
|
||||
/tests/compile/tlastmod
|
||||
/tests/compile/tlinearscanend
|
||||
/tests/compile/tloops
|
||||
/tests/compile/tmacro1
|
||||
/tests/compile/tmacro2
|
||||
/tests/compile/tmacroaspragma
|
||||
/tests/compile/tmacrostmt
|
||||
/tests/compile/tmandelbrot
|
||||
/tests/compile/tmarshal
|
||||
/tests/compile/tmath
|
||||
/tests/compile/tmatrix1
|
||||
/tests/compile/tmatrix2
|
||||
/tests/compile/tmongo
|
||||
/tests/compile/tnamedparamanonproc
|
||||
/tests/compile/tnamedparams
|
||||
/tests/compile/tnestedproc
|
||||
/tests/compile/tnew
|
||||
/tests/compile/tnewsets
|
||||
/tests/compile/tnewuns
|
||||
/tests/compile/tnoargopenarray
|
||||
/tests/compile/tnoforward
|
||||
/tests/compile/tobjconstr2
|
||||
/tests/compile/tobjcov
|
||||
/tests/compile/tobject2
|
||||
/tests/compile/tobject3
|
||||
/tests/compile/tobjects
|
||||
/tests/compile/toop
|
||||
/tests/compile/toptions
|
||||
/tests/compile/tos
|
||||
/tests/compile/toverprc
|
||||
/tests/compile/tparedef
|
||||
/tests/compile/tparscfg
|
||||
/tests/compile/tparsefloat
|
||||
/tests/compile/tparsopt
|
||||
/tests/compile/tposix
|
||||
/tests/compile/tprep
|
||||
/tests/compile/tprocvars
|
||||
/tests/compile/tpush
|
||||
/tests/compile/tquicksort
|
||||
/tests/compile/tquit
|
||||
/tests/compile/tradix
|
||||
/tests/compile/treadln
|
||||
/tests/compile/treadx
|
||||
/tests/compile/trecmod
|
||||
/tests/compile/trecmod2
|
||||
/tests/compile/trectuple
|
||||
/tests/compile/trectuples
|
||||
/tests/compile/tredef
|
||||
/tests/compile/trepr
|
||||
/tests/compile/tsecondarrayproperty
|
||||
/tests/compile/tseq2
|
||||
/tests/compile/tseqcon2
|
||||
/tests/compile/tshadow_magic_type
|
||||
/tests/compile/tsizeof
|
||||
/tests/compile/tslurp
|
||||
/tests/compile/tsockets
|
||||
/tests/compile/tsortcall
|
||||
/tests/compile/tspecialised_is_equivalent
|
||||
/tests/compile/tstrace
|
||||
/tests/compile/tstrdesc
|
||||
/tests/compile/tstrdist
|
||||
/tests/compile/tstreams
|
||||
/tests/compile/tstrset
|
||||
/tests/compile/tstrtabs
|
||||
/tests/compile/ttableconstr
|
||||
/tests/compile/ttempl
|
||||
/tests/compile/ttempl3
|
||||
/tests/compile/ttempl4
|
||||
/tests/compile/ttempl5
|
||||
/tests/compile/ttemplreturntype
|
||||
/tests/compile/tthread_generic
|
||||
/tests/compile/ttime
|
||||
/tests/compile/ttuple1
|
||||
/tests/compile/ttypeclasses
|
||||
/tests/compile/ttypeconverter1
|
||||
/tests/compile/tuserpragma
|
||||
/tests/compile/tvoid
|
||||
/tests/compile/twalker
|
||||
/tests/compile/typalias
|
||||
/tests/dll/client
|
||||
/tests/gc/closureleak
|
||||
/tests/gc/cycleleak
|
||||
/tests/gc/gcbench
|
||||
/tests/gc/gcleak
|
||||
/tests/gc/gcleak2
|
||||
/tests/gc/gcleak3
|
||||
/tests/gc/gctest
|
||||
/tests/gc/weakrefs
|
||||
/tests/manyloc/argument_parser/ex_wget
|
||||
/tests/manyloc/nake/nakefile
|
||||
/tests/manyloc/packages/noconflicts
|
||||
/tests/manyloc/standalone/barebone
|
||||
/tests/patterns/targlist
|
||||
/tests/patterns/tcse
|
||||
/tests/patterns/thoist
|
||||
/tests/patterns/tmatrix
|
||||
/tests/patterns/tnoalias
|
||||
/tests/patterns/tnoendlessrec
|
||||
/tests/patterns/tor
|
||||
/tests/patterns/tpartial
|
||||
/tests/patterns/tstar
|
||||
/tests/patterns/tstmtlist
|
||||
/tests/reject/t99bott
|
||||
/tests/reject/tcheckedfield1
|
||||
/tests/reject/tdeprecated
|
||||
/tests/reject/tdisallowif
|
||||
/tests/reject/tuninit1
|
||||
/tests/rodfiles/aconv
|
||||
/tests/rodfiles/bconv
|
||||
/tests/rodfiles/bmethods
|
||||
/tests/rodfiles/bmethods2
|
||||
/tests/rodfiles/deada
|
||||
/tests/rodfiles/deada2
|
||||
/tests/rodfiles/hallo
|
||||
/tests/rodfiles/hallo2
|
||||
/tests/rodfiles/tgeneric1
|
||||
/tests/rodfiles/tgeneric2
|
||||
/tests/run/tack
|
||||
/tests/run/tactiontable
|
||||
/tests/run/tambsym2
|
||||
/tests/run/tambsys
|
||||
/tests/run/tanontuples
|
||||
/tests/run/tarray
|
||||
/tests/run/tarray2
|
||||
/tests/run/tarray3
|
||||
/tests/run/tarraycons
|
||||
/tests/run/tassert
|
||||
/tests/run/tastoverload1
|
||||
/tests/run/tasynciossl
|
||||
/tests/run/tasyncudp
|
||||
/tests/run/tbind1
|
||||
/tests/run/tbind3
|
||||
/tests/run/tbintre2
|
||||
/tests/run/tbintree
|
||||
/tests/run/tborrow
|
||||
/tests/run/tbug499771
|
||||
/tests/run/tbug511622
|
||||
/tests/run/tcase_setconstr
|
||||
/tests/run/tcasestm
|
||||
/tests/run/tcgbug
|
||||
/tests/run/tclosure2
|
||||
/tests/run/tclosure3
|
||||
/tests/run/tcnstseq
|
||||
/tests/run/tcnstseq2
|
||||
/tests/run/tcnstseq3
|
||||
/tests/run/tconcat
|
||||
/tests/run/tconstr2
|
||||
/tests/run/tcontinue
|
||||
/tests/run/tcontinuexc
|
||||
/tests/run/tcopy
|
||||
/tests/run/tcountup
|
||||
/tests/run/tcritbits
|
||||
/tests/run/tcurrncy
|
||||
/tests/run/tdestructor
|
||||
/tests/run/tdrdobbs_examples
|
||||
/tests/run/temit
|
||||
/tests/run/tenumhole
|
||||
/tests/run/tenumitems
|
||||
/tests/run/teventemitter
|
||||
/tests/run/tevents
|
||||
/tests/run/texceptions
|
||||
/tests/run/texcpt1
|
||||
/tests/run/texcsub
|
||||
/tests/run/texplicitgeneric1
|
||||
/tests/run/tfieldindex
|
||||
/tests/run/tfielditerator
|
||||
/tests/run/tfielditerator2
|
||||
/tests/run/tfilter
|
||||
/tests/run/tfinally
|
||||
/tests/run/tfinally2
|
||||
/tests/run/tfinally3
|
||||
/tests/run/tfinalobj
|
||||
/tests/run/tfloat1
|
||||
/tests/run/tfloat2
|
||||
/tests/run/tfloat3
|
||||
/tests/run/tformat
|
||||
/tests/run/tfriends
|
||||
/tests/run/tgenericassign
|
||||
/tests/run/tgenericassigntuples
|
||||
/tests/run/tgenericconverter
|
||||
/tests/run/tgenericprocvar
|
||||
/tests/run/tgenerics1
|
||||
/tests/run/tgensym
|
||||
/tests/run/tglobal
|
||||
/tests/run/thashes
|
||||
/tests/run/thexlit
|
||||
/tests/run/thintoff
|
||||
/tests/run/tidgen
|
||||
/tests/run/tindent1
|
||||
/tests/run/tinit
|
||||
/tests/run/tinterf
|
||||
/tests/run/tints
|
||||
/tests/run/tisopr
|
||||
/tests/run/titer3
|
||||
/tests/run/titer5
|
||||
/tests/run/titer6
|
||||
/tests/run/titer7
|
||||
/tests/run/titer8
|
||||
/tests/run/titer9
|
||||
/tests/run/titerslice
|
||||
/tests/run/titervaropenarray
|
||||
/tests/run/tkoeniglookup
|
||||
/tests/run/tlet
|
||||
/tests/run/tlists
|
||||
/tests/run/tlocals
|
||||
/tests/run/tlowhigh
|
||||
/tests/run/tmacro2
|
||||
/tests/run/tmacro3
|
||||
/tests/run/tmacro4
|
||||
/tests/run/tmacros1
|
||||
/tests/run/tmath
|
||||
/tests/run/tmatrix
|
||||
/tests/run/tmemoization
|
||||
/tests/run/tmethods1
|
||||
/tests/run/tmixin
|
||||
/tests/run/tmoditer
|
||||
/tests/run/tmultim1
|
||||
/tests/run/tmultim2
|
||||
/tests/run/tmultim3
|
||||
/tests/run/tmultim4
|
||||
/tests/run/tmultim6
|
||||
/tests/run/tnamedenumfields
|
||||
/tests/run/tnestif
|
||||
/tests/run/tnestprc
|
||||
/tests/run/tnewderef
|
||||
/tests/run/tnodeadlocks
|
||||
/tests/run/tobjasgn
|
||||
/tests/run/tobjconstr
|
||||
/tests/run/tobject
|
||||
/tests/run/tofopr
|
||||
/tests/run/tonraise
|
||||
/tests/run/toop1
|
||||
/tests/run/topenarrayrepr
|
||||
/tests/run/topenlen
|
||||
/tests/run/toprprec
|
||||
/tests/run/toverflw
|
||||
/tests/run/toverflw2
|
||||
/tests/run/toverl2
|
||||
/tests/run/toverl3
|
||||
/tests/run/toverwr
|
||||
/tests/run/tovfint
|
||||
/tests/run/tpatterns
|
||||
/tests/run/tpegs
|
||||
/tests/run/tpos
|
||||
/tests/run/tprecedence
|
||||
/tests/run/tprintf
|
||||
/tests/run/tprocvar
|
||||
/tests/run/tquotewords
|
||||
/tests/run/tregex
|
||||
/tests/run/treguse
|
||||
/tests/run/trepr
|
||||
/tests/run/treraise
|
||||
/tests/run/tromans
|
||||
/tests/run/tseqcon
|
||||
/tests/run/tseqtuple
|
||||
/tests/run/tsequtils
|
||||
/tests/run/tsets
|
||||
/tests/run/tsets2
|
||||
/tests/run/tsidee2
|
||||
/tests/run/tsidee3
|
||||
/tests/run/tsimmeth
|
||||
/tests/run/tsimplesort
|
||||
/tests/run/tslices
|
||||
/tests/run/tsortdev
|
||||
/tests/run/tsplit
|
||||
/tests/run/tstempl
|
||||
/tests/run/tstmtexprs
|
||||
/tests/run/tstrange
|
||||
/tests/run/tstringinterp
|
||||
/tests/run/tstrlits
|
||||
/tests/run/tstrutil
|
||||
/tests/run/tsubrange
|
||||
/tests/run/tsubrange2
|
||||
/tests/run/ttables
|
||||
/tests/run/ttables2
|
||||
/tests/run/ttoseq
|
||||
/tests/run/ttypedesc1
|
||||
/tests/run/tunhandledexc
|
||||
/tests/run/tunidecode
|
||||
/tests/run/tunittests
|
||||
/tests/run/tuserassert
|
||||
/tests/run/tvarargs_vs_generic
|
||||
/tests/run/tvardecl
|
||||
/tests/run/tvariantasgn
|
||||
/tests/run/tvariantstack
|
||||
/tests/run/tvarious1
|
||||
/tests/run/tvarnums
|
||||
/tests/run/tvarres1
|
||||
/tests/run/tvarres2
|
||||
/tests/run/tvartup
|
||||
/tests/run/tvtable
|
||||
/tests/run/twrongexc
|
||||
/tests/run/txmlgen
|
||||
/tests/run/txmltree
|
||||
/tests/run/tzeroarray
|
||||
/tests/system/helpers/readall_echo
|
||||
/tests/system/io
|
||||
/tests/system/params
|
||||
/tests/tester
|
||||
/tests/threads/tactors
|
||||
/tests/threads/tactors2
|
||||
/tests/threads/tthreadanalysis2
|
||||
/tests/threads/tthreadanalysis3
|
||||
/tests/threads/tthreadheapviolation1
|
||||
/tools/nimgrep
|
||||
|
||||
@@ -290,6 +290,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
||||
genNamedParamCall(p, e, d)
|
||||
else:
|
||||
genPrefixCall(p, nil, e, d)
|
||||
postStmtActions(p)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
@@ -303,6 +304,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genNamedParamCall(p, ri, d)
|
||||
else:
|
||||
genPrefixCall(p, le, ri, d)
|
||||
postStmtActions(p)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
|
||||
@@ -921,7 +921,12 @@ proc genPragma(p: BProc, n: PNode) =
|
||||
of wEmit: genEmit(p, it)
|
||||
of wBreakpoint: genBreakPoint(p, it)
|
||||
of wWatchpoint: genWatchpoint(p, it)
|
||||
else: nil
|
||||
of wInjectStmt:
|
||||
var p = newProc(nil, p.module)
|
||||
p.options = p.options - {optLineTrace, optStackTrace}
|
||||
genStmts(p, it.sons[1])
|
||||
p.module.injectStmt = p.s(cpsStmts)
|
||||
else: discard
|
||||
|
||||
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
|
||||
if optFieldCheck in p.options:
|
||||
|
||||
@@ -289,6 +289,9 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||
line.toRope, t.info.quotedFilename)
|
||||
|
||||
proc postStmtActions(p: BProc) {.inline.} =
|
||||
app(p.s(cpsStmts), p.module.injectStmt)
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
|
||||
@@ -1119,6 +1122,9 @@ proc newPostInitProc(m: BModule): BProc =
|
||||
# little hack so that unique temporaries are generated:
|
||||
result.labels = 200_000
|
||||
|
||||
proc initProcOptions(m: BModule): TOptions =
|
||||
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
|
||||
|
||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
InitLinkedList(result.headerFiles)
|
||||
@@ -1131,7 +1137,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
result.module = module
|
||||
result.typeInfoMarker = initIntSet()
|
||||
result.initProc = newProc(nil, result)
|
||||
result.initProc.options = gOptions
|
||||
result.initProc.options = initProcOptions(result)
|
||||
result.preInitProc = newPreInitProc(result)
|
||||
result.postInitProc = newPostInitProc(result)
|
||||
initNodeTable(result.dataCache)
|
||||
@@ -1139,7 +1145,12 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
result.forwardedProcs = @[]
|
||||
result.typeNodesName = getTempName()
|
||||
result.nimTypesName = getTempName()
|
||||
result.PreventStackTrace = sfSystemModule in module.flags
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
result.PreventStackTrace = true
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
excl(result.postInitProc.options, optStackTrace)
|
||||
|
||||
proc nullify[T](arr: var T) =
|
||||
for i in low(arr)..high(arr):
|
||||
@@ -1152,7 +1163,7 @@ proc resetModule*(m: var BModule) =
|
||||
m.declaredProtos = initIntSet()
|
||||
initIdTable(m.forwTypeCache)
|
||||
m.initProc = newProc(nil, m)
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
m.preInitProc = newPreInitProc(m)
|
||||
m.postInitProc = newPostInitProc(m)
|
||||
initNodeTable(m.dataCache)
|
||||
@@ -1242,7 +1253,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
var m = BModule(b)
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
|
||||
proc finishModule(m: BModule) =
|
||||
@@ -1329,7 +1340,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
var m = BModule(b)
|
||||
if n != nil:
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
# cached modules need to registered too:
|
||||
registerModuleToMain(m.module)
|
||||
|
||||
@@ -111,6 +111,7 @@ type
|
||||
labels*: natural # for generating unique module-scope names
|
||||
extensionLoaders*: array['0'..'9', PRope] # special procs for the
|
||||
# OpenGL wrapper
|
||||
injectStmt*: PRope
|
||||
|
||||
var
|
||||
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
# semantic checking is done for the code. Cross-references are generated
|
||||
# by knowing how the anchors are going to be named.
|
||||
|
||||
import
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||
importer, sempass2
|
||||
import
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||
importer, sempass2, json
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, PRope]
|
||||
@@ -25,7 +25,7 @@ type
|
||||
indexValFilename: string
|
||||
|
||||
PDoc* = ref TDocumentor
|
||||
|
||||
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
@@ -41,69 +41,69 @@ proc compilerMsgHandler(filename: string, line, col: int,
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
GlobalError(newLineInfo(filename, line, col), k, arg)
|
||||
|
||||
|
||||
proc parseRst(text, filename: string,
|
||||
line, column: int, hasToc: var bool,
|
||||
rstOptions: TRstParseOptions): PRstNode =
|
||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
options.FindFile, compilerMsgHandler)
|
||||
|
||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
||||
new(result)
|
||||
initRstGenerator(result[], (if gCmd != cmdRst2Tex: outHtml else: outLatex),
|
||||
options.gConfigVars, filename, {roSupportRawDirective},
|
||||
options.FindFile, compilerMsgHandler)
|
||||
result.id = 100
|
||||
|
||||
proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
|
||||
proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
|
||||
if gCmd != cmdRst2Tex: appf(dest, xml, args)
|
||||
else: appf(dest, tex, args)
|
||||
|
||||
proc getVarIdx(varnames: openarray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
|
||||
proc getVarIdx(varnames: openarray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
return i
|
||||
result = -1
|
||||
|
||||
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
|
||||
varvalues: openarray[PRope]): PRope =
|
||||
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
|
||||
varvalues: openarray[PRope]): PRope =
|
||||
var i = 0
|
||||
var L = len(frmt)
|
||||
result = nil
|
||||
var num = 0
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '#':
|
||||
of '#':
|
||||
app(result, varvalues[num])
|
||||
inc(num)
|
||||
inc(i)
|
||||
of '$':
|
||||
of '$':
|
||||
app(result, "$")
|
||||
inc(i)
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
while true:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
|
||||
num = j
|
||||
app(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
var id = ""
|
||||
while true:
|
||||
while true:
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
else: rawMessage(errUnkownSubstitionVar, id)
|
||||
of '{':
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
while frmt[i] != '}':
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
@@ -124,17 +124,17 @@ proc genComment(d: PDoc, n: PNode): string =
|
||||
var dummyHasToc: bool
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||
toLineNumber(n.info), toColumn(n.info),
|
||||
toLineNumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options + {roSkipPounds}), result)
|
||||
|
||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||
if n == nil: return nil
|
||||
result = genComment(d, n).toRope
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
if n.kind notin {nkEmpty..nkNilLit}:
|
||||
for i in countup(0, len(n)-1):
|
||||
result = genRecComment(d, n.sons[i])
|
||||
if result != nil: return
|
||||
if result != nil: return
|
||||
else:
|
||||
n.comment = nil
|
||||
|
||||
@@ -158,10 +158,10 @@ proc extractDocComment*(s: PSym, d: PDoc = nil): string =
|
||||
else:
|
||||
result = n.comment.substr(2).replace("\n##", "\n").strip
|
||||
|
||||
proc isVisible(n: PNode): bool =
|
||||
proc isVisible(n: PNode): bool =
|
||||
result = false
|
||||
if n.kind == nkPostfix:
|
||||
if n.len == 2 and n.sons[0].kind == nkIdent:
|
||||
if n.kind == nkPostfix:
|
||||
if n.len == 2 and n.sons[0].kind == nkIdent:
|
||||
var v = n.sons[0].ident
|
||||
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
||||
elif n.kind == nkSym:
|
||||
@@ -171,36 +171,36 @@ proc isVisible(n: PNode): bool =
|
||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(n.sons[0])
|
||||
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
case n.kind
|
||||
of nkPostfix: result = getName(d, n.sons[1], splitAfter)
|
||||
of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
|
||||
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
|
||||
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
|
||||
of nkAccQuoted:
|
||||
result = esc(d.target, "`")
|
||||
of nkAccQuoted:
|
||||
result = esc(d.target, "`")
|
||||
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
|
||||
result.add esc(d.target, "`")
|
||||
else:
|
||||
internalError(n.info, "getName()")
|
||||
result = ""
|
||||
|
||||
proc getRstName(n: PNode): PRstNode =
|
||||
proc getRstName(n: PNode): PRstNode =
|
||||
case n.kind
|
||||
of nkPostfix: result = getRstName(n.sons[1])
|
||||
of nkPragmaExpr: result = getRstName(n.sons[0])
|
||||
of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
|
||||
of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
|
||||
of nkAccQuoted:
|
||||
of nkAccQuoted:
|
||||
result = getRstName(n.sons[0])
|
||||
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
|
||||
else:
|
||||
internalError(n.info, "getRstName()")
|
||||
result = nil
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(nameNode): return
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(nameNode): return
|
||||
var name = toRope(getName(d, nameNode))
|
||||
var result: PRope = nil
|
||||
var literal = ""
|
||||
@@ -208,73 +208,89 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
var comm = genRecComment(d, n) # call this here for the side-effect!
|
||||
var r: TSrcGen
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
while true:
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
case kind
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
[toRope(literal)])
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
of tkSpaces, tkInvalid:
|
||||
app(result, literal)
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
inc(d.id)
|
||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
["name", "header", "desc", "itemID"],
|
||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
["name", "header", "desc", "itemID"],
|
||||
[name, result, comm, toRope(d.id)]))
|
||||
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
["name", "header", "desc", "itemID"], [
|
||||
toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
|
||||
setIndexTerm(d[], $d.id, getName(d, nameNode))
|
||||
|
||||
proc checkForFalse(n: PNode): bool =
|
||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
|
||||
if not isVisible(nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
comm = genRecComment(d, n).ropeToStr()
|
||||
r: TSrcGen
|
||||
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
|
||||
result = %{ "name": %name, "type": %($k) }
|
||||
|
||||
if comm != nil and comm != "":
|
||||
result["description"] = %comm
|
||||
if r.buf != nil:
|
||||
result["code"] = %r.buf
|
||||
|
||||
proc checkForFalse(n: PNode): bool =
|
||||
result = n.kind == nkIdent and IdentEq(n.ident, "false")
|
||||
|
||||
proc traceDeps(d: PDoc, n: PNode) =
|
||||
|
||||
proc traceDeps(d: PDoc, n: PNode) =
|
||||
const k = skModule
|
||||
if d.section[k] != nil: app(d.section[k], ", ")
|
||||
dispA(d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
dispA(d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
"$1", [toRope(getModuleName(n))])
|
||||
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
of nkCommentStmt: app(d.modDesc, genComment(d, n))
|
||||
of nkProcDef:
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skProc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skMethod)
|
||||
of nkIteratorDef:
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
||||
@@ -284,27 +300,69 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
||||
genItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
|
||||
of nkWhenStmt:
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]):
|
||||
generateDoc(d, lastSon(n.sons[0]))
|
||||
of nkImportStmt:
|
||||
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
|
||||
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
else: nil
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
let stripped = n.comment.substr(2).strip
|
||||
result = %{ "comment": %stripped }
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skProc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMethod)
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMacro)
|
||||
of nkTemplateDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skTemplate)
|
||||
of nkConverterDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
var elem = jArray
|
||||
if elem == nil: elem = newJArray()
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var r = generateJson(d, n.sons[i], elem)
|
||||
if r != nil:
|
||||
elem.add(r)
|
||||
if result == nil: result = elem
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
|
||||
discard generateJson(d, lastSon(n.sons[0]), jArray)
|
||||
else: nil
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
const sectionNames: array[skModule..skTemplate, string] = [
|
||||
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
|
||||
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
|
||||
"Iterators", "Converters", "Macros", "Templates"
|
||||
]
|
||||
if d.section[kind] == nil: return
|
||||
if d.section[kind] == nil: return
|
||||
var title = sectionNames[kind].toRope
|
||||
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
@@ -313,7 +371,7 @@ proc genSection(d: PDoc, kind: TSymKind) =
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
|
||||
|
||||
proc genOutFile(d: PDoc): PRope =
|
||||
proc genOutFile(d: PDoc): PRope =
|
||||
var
|
||||
code, content: PRope
|
||||
title = ""
|
||||
@@ -321,7 +379,7 @@ proc genOutFile(d: PDoc): PRope =
|
||||
var tmp = ""
|
||||
renderTocEntries(d[], j, 1, tmp)
|
||||
var toc = tmp.toRope
|
||||
for i in countup(low(TSymKind), high(TSymKind)):
|
||||
for i in countup(low(TSymKind), high(TSymKind)):
|
||||
genSection(d, i)
|
||||
app(toc, d.toc[i])
|
||||
if toc != nil:
|
||||
@@ -329,30 +387,30 @@ proc genOutFile(d: PDoc): PRope =
|
||||
for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
|
||||
if d.meta[metaTitle].len != 0: title = d.meta[metaTitle]
|
||||
else: title = "Module " & extractFilename(changeFileExt(d.filename, ""))
|
||||
|
||||
|
||||
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time", "content"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), code])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
d.meta[metaVersion].toRope])
|
||||
else:
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in gGlobalOptions:
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
splitFile(d.filename).name & indexExt)
|
||||
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
var content = genOutFile(d)
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
@@ -361,7 +419,7 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
|
||||
proc CommandDoc*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
if ast == nil: return
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
generateDoc(d, ast)
|
||||
@@ -388,12 +446,26 @@ proc CommandRst2TeX*() =
|
||||
splitter = "\\-"
|
||||
CommandRstAux(gProjectFull, TexExt)
|
||||
|
||||
proc CommandJSON*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
var json = generateJson(d, ast)
|
||||
var content = newRope(pretty(json))
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
echo getOutFile(gProjectFull, JsonExt)
|
||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||
|
||||
proc CommandBuildIndex*() =
|
||||
var content = mergeIndexes(gProjectFull).toRope
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, nil, nil])
|
||||
writeRope(code, getOutFile("theindex", HtmlExt))
|
||||
|
||||
@@ -463,9 +463,9 @@ proc getCompileOptions: string =
|
||||
proc getLinkOptions: string =
|
||||
result = linkOptions
|
||||
for linkedLib in items(cLinkedLibs):
|
||||
result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteIfContainsWhite)
|
||||
result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteShell)
|
||||
for libDir in items(cLibs):
|
||||
result.add([cc[ccompiler].linkDirCmd, libDir.quoteIfContainsWhite])
|
||||
result.add([cc[ccompiler].linkDirCmd, libDir.quoteShell])
|
||||
|
||||
proc needsExeExt(): bool {.inline.} =
|
||||
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||
@@ -485,10 +485,10 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
var includeCmd, compilePattern: string
|
||||
if not noAbsolutePaths():
|
||||
# compute include paths:
|
||||
includeCmd = cc[c].includeCmd & quoteIfContainsWhite(libpath)
|
||||
includeCmd = cc[c].includeCmd & quoteShell(libpath)
|
||||
|
||||
for includeDir in items(cIncludes):
|
||||
includeCmd.add([cc[c].includeCmd, includeDir.quoteIfContainsWhite])
|
||||
includeCmd.add([cc[c].includeCmd, includeDir.quoteShell])
|
||||
|
||||
compilePattern = JoinPath(ccompilerpath, exe)
|
||||
else:
|
||||
@@ -501,17 +501,17 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
toObjFile(cfile)
|
||||
else:
|
||||
completeCFilePath(toObjFile(cfile))
|
||||
cfile = quoteIfContainsWhite(AddFileExt(cfile, cExt))
|
||||
objfile = quoteIfContainsWhite(objfile)
|
||||
result = quoteIfContainsWhite(compilePattern % [
|
||||
cfile = quoteShell(AddFileExt(cfile, cExt))
|
||||
objfile = quoteShell(objfile)
|
||||
result = quoteShell(compilePattern % [
|
||||
"file", cfile, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
add(result, ' ')
|
||||
addf(result, cc[c].compileTmpl, [
|
||||
"file", cfile, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||
"lib", quoteIfContainsWhite(libpath)])
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
|
||||
proc footprint(filename: string): TCrc32 =
|
||||
result = crcFromFile(filename) ><
|
||||
@@ -590,7 +590,7 @@ proc CallCCompiler*(projectfile: string) =
|
||||
while it != nil:
|
||||
let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteIfContainsWhite(
|
||||
add(objfiles, quoteShell(
|
||||
addFileExt(objFile, cc[ccompiler].objExt)))
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
@@ -602,8 +602,8 @@ proc CallCCompiler*(projectfile: string) =
|
||||
var linkerExe = getConfigVar(c, ".linkerexe")
|
||||
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
|
||||
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(): linkCmd = quoteIfContainsWhite(linkerExe)
|
||||
else: linkCmd = quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe))
|
||||
if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
|
||||
else: linkCmd = quoteShell(JoinPath(ccompilerpath, linkerExe))
|
||||
if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
|
||||
else: buildGui = ""
|
||||
var exefile: string
|
||||
@@ -616,18 +616,19 @@ proc CallCCompiler*(projectfile: string) =
|
||||
if options.outFile.len > 0:
|
||||
exefile = options.outFile
|
||||
if not noAbsolutePaths():
|
||||
exefile = joinPath(splitFile(projectFile).dir, exefile)
|
||||
exefile = quoteIfContainsWhite(exefile)
|
||||
if not exeFile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectFile).dir, exefile)
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions()
|
||||
linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll,
|
||||
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
linkCmd.add ' '
|
||||
addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions,
|
||||
"objfiles", objfiles, "exefile", exefile,
|
||||
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||
"lib", quoteIfContainsWhite(libpath)])
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
||||
else:
|
||||
linkCmd = ""
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
# implements the command dispatcher and several commands
|
||||
|
||||
import
|
||||
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
|
||||
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,
|
||||
@@ -98,7 +98,7 @@ proc CommandCompileToC =
|
||||
# rodread.rodcompilerProcs
|
||||
# rodread.gTypeTable
|
||||
# rodread.gMods
|
||||
|
||||
|
||||
# !! ropes.cache
|
||||
# semthreads.computed?
|
||||
#
|
||||
@@ -166,7 +166,7 @@ proc commandEval(exp: string) =
|
||||
proc CommandPrettyOld =
|
||||
var projectFile = addFileExt(mainCommandArg(), NimExt)
|
||||
var module = parseFile(projectFile.fileInfoIdx)
|
||||
if module != nil:
|
||||
if module != nil:
|
||||
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
||||
|
||||
proc CommandPretty =
|
||||
@@ -175,24 +175,24 @@ proc CommandPretty =
|
||||
registerPass(prettyPass)
|
||||
compileProject()
|
||||
pretty.overwriteFiles()
|
||||
|
||||
|
||||
proc CommandScan =
|
||||
var f = addFileExt(mainCommandArg(), nimExt)
|
||||
var stream = LLStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
if stream != nil:
|
||||
var
|
||||
L: TLexer
|
||||
tok: TToken
|
||||
initToken(tok)
|
||||
openLexer(L, f, stream)
|
||||
while true:
|
||||
while true:
|
||||
rawGetTok(L, tok)
|
||||
PrintTok(tok)
|
||||
if tok.tokType == tkEof: break
|
||||
if tok.tokType == tkEof: break
|
||||
CloseLexer(L)
|
||||
else:
|
||||
else:
|
||||
rawMessage(errCannotOpenFile, f)
|
||||
|
||||
|
||||
proc CommandSuggest =
|
||||
if isServing:
|
||||
# XXX: hacky work-around ahead
|
||||
@@ -246,7 +246,7 @@ proc resetMemory =
|
||||
for i in low(buckets)..high(buckets):
|
||||
buckets[i] = nil
|
||||
idAnon = nil
|
||||
|
||||
|
||||
# XXX: clean these global vars
|
||||
# ccgstmts.gBreakpoints
|
||||
# ccgthreadvars.nimtv
|
||||
@@ -262,7 +262,7 @@ proc resetMemory =
|
||||
# rodread.rodcompilerProcs
|
||||
# rodread.gTypeTable
|
||||
# rodread.gMods
|
||||
|
||||
|
||||
# !! ropes.cache
|
||||
# semthreads.computed?
|
||||
#
|
||||
@@ -289,7 +289,7 @@ const
|
||||
proc MainCommand* =
|
||||
when SimiluateCaasMemReset:
|
||||
gGlobalOptions.incl(optCaasEnabled)
|
||||
|
||||
|
||||
# In "nimrod serve" scenario, each command must reset the registered passes
|
||||
clearPasses()
|
||||
gLastCmdTime = epochTime()
|
||||
@@ -301,7 +301,7 @@ proc MainCommand* =
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
case command.normalize
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
# compile means compileToC currently
|
||||
gCmd = cmdCompileToC
|
||||
wantMainModule()
|
||||
@@ -325,13 +325,13 @@ proc MainCommand* =
|
||||
when hasTinyCBackend:
|
||||
extccomp.setCC("tcc")
|
||||
CommandCompileToC()
|
||||
else:
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
of "js", "compiletojs":
|
||||
of "js", "compiletojs":
|
||||
gCmd = cmdCompileToJS
|
||||
wantMainModule()
|
||||
CommandCompileToJS()
|
||||
of "compiletollvm":
|
||||
of "compiletollvm":
|
||||
gCmd = cmdCompileToLLVM
|
||||
wantMainModule()
|
||||
when has_LLVM_Backend:
|
||||
@@ -353,21 +353,27 @@ proc MainCommand* =
|
||||
wantMainModule()
|
||||
DefineSymbol("nimdoc")
|
||||
CommandDoc2()
|
||||
of "rst2html":
|
||||
of "rst2html":
|
||||
gCmd = cmdRst2html
|
||||
LoadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
CommandRst2Html()
|
||||
of "rst2tex":
|
||||
of "rst2tex":
|
||||
gCmd = cmdRst2tex
|
||||
LoadConfigs(DocTexConfig)
|
||||
wantMainModule()
|
||||
CommandRst2TeX()
|
||||
of "jsondoc":
|
||||
gCmd = cmdDoc
|
||||
LoadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
DefineSymbol("nimdoc")
|
||||
CommandJSON()
|
||||
of "buildindex":
|
||||
gCmd = cmdDoc
|
||||
LoadConfigs(DocConfig)
|
||||
CommandBuildIndex()
|
||||
of "gendepend":
|
||||
of "gendepend":
|
||||
gCmd = cmdGenDepend
|
||||
wantMainModule()
|
||||
CommandGenDepend()
|
||||
@@ -400,16 +406,16 @@ proc MainCommand* =
|
||||
gCmd = cmdCheck
|
||||
wantMainModule()
|
||||
CommandCheck()
|
||||
of "parse":
|
||||
of "parse":
|
||||
gCmd = cmdParse
|
||||
wantMainModule()
|
||||
discard parseFile(gProjectMainIdx)
|
||||
of "scan":
|
||||
of "scan":
|
||||
gCmd = cmdScan
|
||||
wantMainModule()
|
||||
CommandScan()
|
||||
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||
of "i":
|
||||
of "i":
|
||||
gCmd = cmdInteractive
|
||||
CommandInteractive()
|
||||
of "e":
|
||||
@@ -427,11 +433,11 @@ proc MainCommand* =
|
||||
of "serve":
|
||||
isServing = true
|
||||
gGlobalOptions.incl(optCaasEnabled)
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
serve(MainCommand)
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
|
||||
|
||||
if (msgs.gErrorCounter == 0 and
|
||||
gCmd notin {cmdInterpret, cmdRun, cmdDump} and
|
||||
gVerbosity > 0):
|
||||
|
||||
@@ -13,9 +13,9 @@ when defined(gcc) and defined(windows):
|
||||
else:
|
||||
{.link: "icons/nimrod_icon.o".}
|
||||
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, platform, main, parseopt, service
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, osproc, platform, main, parseopt, service
|
||||
|
||||
when hasTinyCBackend:
|
||||
import tccgen
|
||||
@@ -23,7 +23,7 @@ when hasTinyCBackend:
|
||||
when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
|
||||
proc prependCurDir(f: string): string =
|
||||
when defined(unix):
|
||||
if os.isAbsolute(f): result = f
|
||||
@@ -61,12 +61,18 @@ proc HandleCmdLine() =
|
||||
tccgen.run()
|
||||
if optRun in gGlobalOptions:
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex = quoteIfContainsWhite(
|
||||
var ex = quoteShell(
|
||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||
execExternalProgram("node " & ex & ' ' & service.arguments)
|
||||
else:
|
||||
var ex = quoteIfContainsWhite(
|
||||
changeFileExt(gProjectFull, exeExt).prependCurDir)
|
||||
var binPath: string
|
||||
if options.outFile.len > 0:
|
||||
# If the user specified an outFile path, use that directly.
|
||||
binPath = options.outFile.prependCurDir
|
||||
else:
|
||||
# Figure out ourselves a valid binary name.
|
||||
binPath = changeFileExt(gProjectFull, exeExt).prependCurDir
|
||||
var ex = quoteShell(binPath)
|
||||
execExternalProgram(ex & ' ' & service.arguments)
|
||||
|
||||
when defined(GC_setMaxPause):
|
||||
|
||||
@@ -132,6 +132,7 @@ const
|
||||
NimExt* = "nim"
|
||||
RodExt* = "rod"
|
||||
HtmlExt* = "html"
|
||||
JsonExt* = "json"
|
||||
TexExt* = "tex"
|
||||
IniExt* = "ini"
|
||||
DefaultConfig* = "nimrod.cfg"
|
||||
|
||||
@@ -43,7 +43,8 @@ const
|
||||
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
|
||||
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto}
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||
wInjectStmt}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
|
||||
@@ -722,6 +723,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wOperator:
|
||||
if sym == nil: invalidPragma(it)
|
||||
else: sym.position = expectIntLit(c, it)
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
else:
|
||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
|
||||
@@ -380,7 +380,8 @@ proc analyseThreadProc*(prc: PSym) =
|
||||
var formals = skipTypes(prc.typ, abstractInst).n
|
||||
for i in 1 .. formals.len-1:
|
||||
var formal = formals.sons[i].sym
|
||||
c.mapping[formal.id] = toTheirs # thread receives foreign data!
|
||||
# the input is copied and belongs to the thread:
|
||||
c.mapping[formal.id] = toMine
|
||||
discard analyse(c, prc.getBody)
|
||||
|
||||
proc needsGlobalAnalysis*: bool =
|
||||
|
||||
@@ -60,7 +60,7 @@ type
|
||||
wPassc, wPassl, wBorrow, wDiscardable,
|
||||
wFieldChecks,
|
||||
wWatchPoint, wSubsChar,
|
||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
|
||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||
wNoStackFrame,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl,
|
||||
@@ -142,7 +142,8 @@ const
|
||||
"compiletime", "noinit",
|
||||
"passc", "passl", "borrow", "discardable", "fieldchecks",
|
||||
"watchpoint",
|
||||
"subschar", "acyclic", "shallow", "unroll", "linearscanend", "computedgoto",
|
||||
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||
"computedgoto", "injectstmt",
|
||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||
"nostackframe", "implicitstatic", "global", "codegendecl",
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
.. contents::
|
||||
|
||||
|
||||
.. raw:: html
|
||||
<blockquote><p>
|
||||
"yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
|
||||
</p></blockquote>
|
||||
|
||||
Nimrod differs from many other compilers in that it is really fast,
|
||||
and being so fast makes it suited to provide external queries for
|
||||
text editors about the source code being written. Through the
|
||||
@@ -522,21 +527,6 @@ At the moment idetools support is still in development so the test
|
||||
suite is not integrated with the main test suite and you have to
|
||||
run it manually. First you have to compile the tester::
|
||||
|
||||
$ cd my/nimrod/checkout
|
||||
$ nimrod c tests/tester.nim
|
||||
|
||||
Running the tester without parameters will display some options.
|
||||
To run the caas test suite (and other special tests) you need to
|
||||
use the `special` command. You need to run this command from the
|
||||
root of the checkout or it won't be able to open the required files::
|
||||
|
||||
$ ./tests/tester special
|
||||
|
||||
However this is a roundabout way of running the test suite. You can
|
||||
also compile and run ``tests/caasdriver.nim`` manually. In fact,
|
||||
running it manually will allow you to specify special parameters
|
||||
too. Example::
|
||||
|
||||
$ cd my/nimrod/checkout/tests
|
||||
$ nimrod c caasdriver.nim
|
||||
|
||||
|
||||
@@ -4708,7 +4708,11 @@ fatal pragma
|
||||
------------
|
||||
The `fatal`:idx: pragma is used to make the compiler output an error message
|
||||
with the given content. In contrast to the ``error`` pragma, compilation
|
||||
is guaranteed to be aborted by this pragma.
|
||||
is guaranteed to be aborted by this pragma. Example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
when not defined(objc):
|
||||
{.fatal: "Compile this program with the objc command!".}
|
||||
|
||||
warning pragma
|
||||
--------------
|
||||
@@ -5053,6 +5057,18 @@ Note that this pragma is somewhat of a misnomer: Other backends will provide
|
||||
the same feature under the same name.
|
||||
|
||||
|
||||
Extern pragma
|
||||
-------------
|
||||
Like ``exportc`` or ``importc`` the `extern`:idx: pragma affects name
|
||||
mangling. The string literal passed to ``extern`` can be a format string:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
proc p(s: string) {.extern: "prefix$1".} =
|
||||
echo s
|
||||
|
||||
In the example the external name of ``p`` is set to ``prefixp``.
|
||||
|
||||
|
||||
Bycopy pragma
|
||||
-------------
|
||||
|
||||
|
||||
@@ -468,6 +468,19 @@ proc is declared in the generated code:
|
||||
|
||||
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
|
||||
echo "realistic interrupt handler"
|
||||
|
||||
|
||||
InjectStmt pragma
|
||||
-----------------
|
||||
|
||||
The `injectStmt`:idx: pragma can be used to inject a statement before every
|
||||
other statement in the current module. It is only supposed to be used for
|
||||
debugging:
|
||||
|
||||
.. code-block:: nimrod
|
||||
{.injectStmt: gcInvariants().}
|
||||
|
||||
# ... complex code here that produces crashes ...
|
||||
|
||||
|
||||
LineDir option
|
||||
|
||||
11
examples/cgi/cgi_server.py
Normal file
11
examples/cgi/cgi_server.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
import BaseHTTPServer
|
||||
import CGIHTTPServer
|
||||
|
||||
server = BaseHTTPServer.HTTPServer
|
||||
handler = CGIHTTPServer.CGIHTTPRequestHandler
|
||||
server_address = ('localhost', 8008)
|
||||
handler.cgi_directories = ['/']
|
||||
|
||||
httpd = server(server_address, handler)
|
||||
httpd.serve_forever()
|
||||
5
examples/cgi/cgi_stacktrace.nim
Normal file
5
examples/cgi/cgi_stacktrace.nim
Normal file
@@ -0,0 +1,5 @@
|
||||
import cgi
|
||||
cgi.setStackTraceStdout()
|
||||
|
||||
var a: string = nil
|
||||
a.add "foobar"
|
||||
7
examples/cgi/example.nim
Normal file
7
examples/cgi/example.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
import cgi
|
||||
|
||||
write(stdout, "Content-type: text/html\n\n")
|
||||
write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
|
||||
write(stdout, "<html><head><title>Test</title></head><body>\n")
|
||||
write(stdout, "Hello!")
|
||||
writeln(stdout, "</body></html>")
|
||||
@@ -274,6 +274,8 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## macro check(ex: expr): stmt =
|
||||
## # this is a simplified version of the check macro from the
|
||||
## # unittest module.
|
||||
@@ -296,6 +298,8 @@ template emit*(e: expr[string]): stmt =
|
||||
## that should be inserted verbatim in the program
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||
##
|
||||
eval: result = e.parseStmt
|
||||
@@ -480,6 +484,34 @@ proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
|
||||
proc newIdentDefs*(name, kind: PNimrodNode;
|
||||
default = newEmptyNode()): PNimrodNode {.compileTime.} =
|
||||
## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
|
||||
##
|
||||
## ``nnkIdentDefs`` need to have at least three children, but they can have
|
||||
## more: first comes a list of identifiers followed by a type and value
|
||||
## nodes. This helper proc creates a three node subtree, the first subnode
|
||||
## being a single identifier name. Both the ``kind`` node and ``default``
|
||||
## (value) nodes may be empty depending on where the ``nnkIdentDefs``
|
||||
## appears: tuple or object definitions will have an empty ``default`` node,
|
||||
## ``let`` or ``var`` blocks may have an empty ``kind`` node if the
|
||||
## identifier is being assigned a value. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## var varSection = newNimNode(nnkVarSection).add(
|
||||
## newIdentDefs(ident("a"), ident("string")),
|
||||
## newIdentDefs(ident("b"), newEmptyNode(), newLit(3)))
|
||||
## # --> var
|
||||
## # a: string
|
||||
## # b = 3
|
||||
##
|
||||
## If you need to create multiple identifiers you need to use the lower level
|
||||
## ``newNimNode``:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## result = newNimNode(nnkIdentDefs).add(
|
||||
## ident("a"), ident("b"), ident("c"), ident("string"),
|
||||
## newStrLitNode("Hello"))
|
||||
newNimNode(nnkIdentDefs).add(name, kind, default)
|
||||
|
||||
proc newNilLit*(): PNimrodNode {.compileTime.} =
|
||||
@@ -503,11 +535,11 @@ from strutils import cmpIgnoreStyle, format
|
||||
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
|
||||
assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
|
||||
|
||||
proc newProc*(name = newEmptyNode(); params: openarray[PNimrodNode] = [];
|
||||
proc newProc*(name = newEmptyNode(); params: openarray[PNimrodNode] = [newEmptyNode()];
|
||||
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
||||
## shortcut for creating a new proc
|
||||
##
|
||||
## The ``params`` array should start with the return type of the proc,
|
||||
## The ``params`` array must start with the return type of the proc,
|
||||
## followed by a list of IdentDefs which specify the params.
|
||||
assert procType in RoutineNodes
|
||||
result = newNimNode(procType).add(
|
||||
|
||||
@@ -7,7 +7,18 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements a generator of HTML/Latex from `reStructuredText`:idx:.
|
||||
## This module implements a generator of HTML/Latex from
|
||||
## `reStructuredText`:idx: (see http://docutils.sourceforge.net/rst.html for
|
||||
## information on this markup syntax). You can generate HTML output through the
|
||||
## convenience proc ``rstToHtml``, which provided an input string with rst
|
||||
## markup returns a string with the generated HTML. The final output is meant
|
||||
## to be embedded inside a full document you provide yourself, so it won't
|
||||
## contain the usual ``<header>`` or ``<body>`` parts.
|
||||
##
|
||||
## You can also create a ``TRstGenerator`` structure and populate it with the
|
||||
## other lower level methods to finally build complete documents. This requires
|
||||
## many options and tweaking, but you are not limited to snippets and can
|
||||
## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
|
||||
|
||||
import strutils, os, hashes, strtabs, rstast, rst, highlite
|
||||
|
||||
@@ -40,13 +51,51 @@ type
|
||||
filename*: string
|
||||
meta*: array[TMetaEnum, string]
|
||||
|
||||
PDoc = var TRstGenerator
|
||||
PDoc = var TRstGenerator ## Alias to type less.
|
||||
|
||||
proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
|
||||
config: PStringTable, filename: string,
|
||||
options: TRstParseOptions,
|
||||
findFile: TFindFileHandler,
|
||||
msgHandler: TMsgHandler) =
|
||||
## Initializes a ``TRstGenerator``.
|
||||
##
|
||||
## You need to call this before using a ``TRstGenerator`` with any other
|
||||
## procs in this module. Pass a non ``nil`` ``PStringTable`` value as
|
||||
## ``config`` with parameters used by the HTML output generator. If you
|
||||
## don't know what to use, pass the results of the ``defaultConfig()`` proc.
|
||||
## The ``filename`` is symbolic and used only for error reporting, you can
|
||||
## pass any non ``nil`` string here.
|
||||
##
|
||||
## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
|
||||
## are defined in the the `packages/docutils/rst module <rst.html>`_.
|
||||
## ``options`` selects the behaviour of the rst parser.
|
||||
##
|
||||
## ``findFile`` is a proc used by the rst ``include`` directive among others.
|
||||
## The purpose of this proc is to mangle or filter paths. It receives paths
|
||||
## specified in the rst document and has to return a valid path to existing
|
||||
## files or the empty string otherwise. If you pass ``nil``, a default proc
|
||||
## will be used which given a path returns the input path only if the file
|
||||
## exists. One use for this proc is to transform relative paths found in the
|
||||
## document to absolute path, useful if the rst file and the resources it
|
||||
## references are not in the same directory as the current working directory.
|
||||
##
|
||||
## The ``msgHandler`` is a proc used for user error reporting. It will be
|
||||
## called with the filename, line, col, and type of any error found during
|
||||
## parsing. If you pass ``nil``, a default message handler will be used which
|
||||
## writes the messages to the standard output.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## import packages/docutils/rstgen
|
||||
##
|
||||
## var gen: TRstGenerator
|
||||
##
|
||||
## gen.initRstGenerator(outHtml, defaultConfig(),
|
||||
## "filename", {}, nil, nil)
|
||||
|
||||
g.config = config
|
||||
g.target = target
|
||||
g.tocPart = @[]
|
||||
@@ -147,7 +196,19 @@ proc dispA(target: TOutputTarget, dest: var string,
|
||||
if target != outLatex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
proc renderRstToOut*(d: PDoc, n: PRstNode, result: var string)
|
||||
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
|
||||
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
|
||||
##
|
||||
## Before using this proc you need to initialise a ``TRstGenerator`` with
|
||||
## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
|
||||
## `packages/docutils/rst module <rst.html>`_. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## # ...configure gen and rst vars...
|
||||
## var generatedHTML = ""
|
||||
## renderRstToOut(gen, rst, generatedHTML)
|
||||
## echo generatedHTML
|
||||
|
||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
|
||||
@@ -162,7 +223,7 @@ proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
|
||||
|
||||
# ---------------- index handling --------------------------------------------
|
||||
|
||||
proc setIndexTerm*(d: PDoc, id, term: string) =
|
||||
proc setIndexTerm*(d: var TRstGenerator, id, term: string) =
|
||||
d.theIndex.add(term)
|
||||
d.theIndex.add('\t')
|
||||
let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
|
||||
@@ -295,7 +356,7 @@ proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
|
||||
|
||||
proc renderTocEntries*(d: PDoc, j: var int, lvl: int, result: var string) =
|
||||
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int, result: var string) =
|
||||
var tmp = ""
|
||||
while j <= high(d.tocPart):
|
||||
var a = abs(d.tocPart[j].n.level)
|
||||
@@ -678,8 +739,26 @@ $content
|
||||
|
||||
proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
config: PStringTable): string =
|
||||
## exported for *nimforum*.
|
||||
|
||||
## Converts an input rst string into embeddable HTML.
|
||||
##
|
||||
## This convenience proc parses any input string using rst markup (it doesn't
|
||||
## have to be a full document!) and returns an embeddable piece of HTML. The
|
||||
## proc is meant to be used in *online* environments without access to a
|
||||
## meaningful filesystem, and therefore rst ``include`` like directives won't
|
||||
## work. For an explanation of the ``config`` parameter see the
|
||||
## ``initRstGenerator`` proc. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## import packages/docutils/rstgen, strtabs
|
||||
##
|
||||
## echo rstToHtml("*Hello* **world**!", {},
|
||||
## newStringTable(modeStyleInsensitive))
|
||||
## # --> <em>Hello</em> <strong>world</strong>!
|
||||
##
|
||||
## If you need to allow the rst ``include`` directive or tweak the generated
|
||||
## output you have to create your own ``TRstGenerator`` with
|
||||
## ``initRstGenerator`` and related procs.
|
||||
|
||||
proc myFindFile(filename: string): string =
|
||||
# we don't find any files in online mode:
|
||||
result = ""
|
||||
@@ -692,4 +771,8 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
|
||||
result = ""
|
||||
renderRstToOut(d, rst, result)
|
||||
|
||||
|
||||
|
||||
when isMainModule:
|
||||
echo rstToHtml("*Hello* **world**!", {},
|
||||
newStringTable(modeStyleInsensitive))
|
||||
|
||||
@@ -33,10 +33,10 @@ proc openDefaultBrowser*(url: string) =
|
||||
else:
|
||||
discard ShellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
|
||||
elif defined(macosx):
|
||||
discard execShellCmd("open " & quoteIfContainsWhite(url))
|
||||
discard execShellCmd("open " & quoteShell(url))
|
||||
else:
|
||||
const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
|
||||
var u = quoteIfContainsWhite(url)
|
||||
var u = quoteShell(url)
|
||||
for a in items(attempts):
|
||||
if execShellCmd(a & u) == 0: return
|
||||
for b in getEnv("BROWSER").string.split(PathSep):
|
||||
|
||||
@@ -342,16 +342,35 @@ proc writeContentType*() =
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
## write(stdout, "Content-type: text/html\n\n")
|
||||
##
|
||||
## It also modifies the debug stack traces so that they contain
|
||||
## ``<br />`` and are easily readable in a browser.
|
||||
write(stdout, "Content-type: text/html\n\n")
|
||||
system.stackTraceNewLine = "<br />\n"
|
||||
|
||||
proc setStackTraceNewLine*() =
|
||||
## Modifies the debug stack traces so that they contain
|
||||
## ``<br />`` and are easily readable in a browser.
|
||||
system.stackTraceNewLine = "<br />\n"
|
||||
proc resetForStacktrace() =
|
||||
stdout.write """<!--: spam
|
||||
Content-Type: text/html
|
||||
|
||||
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> -->
|
||||
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> -->
|
||||
</font> </font> </font> </script> </object> </blockquote> </pre>
|
||||
</table> </table> </table> </table> </table> </font> </font> </font>
|
||||
"""
|
||||
|
||||
proc writeErrorMessage*(data: string) =
|
||||
## Tries to reset browser state and writes `data` to stdout in
|
||||
## <plaintext> tag.
|
||||
resetForStacktrace()
|
||||
# We use <plaintext> here, instead of escaping, so stacktrace can
|
||||
# be understood by human looking at source.
|
||||
stdout.write("<plaintext>\n")
|
||||
stdout.write(data)
|
||||
|
||||
proc setStackTraceStdout*() =
|
||||
## Makes Nimrod output stacktraces to stdout, instead of server log.
|
||||
errorMessageWriter = writeErrorMessage
|
||||
|
||||
proc setStackTraceNewLine*() {.deprecated.} =
|
||||
## Makes Nimrod output stacktraces to stdout, instead of server log.
|
||||
## Depracated alias for setStackTraceStdout.
|
||||
setStackTraceStdout()
|
||||
|
||||
proc setCookie*(name, value: string) =
|
||||
## Sets a cookie.
|
||||
@@ -374,4 +393,3 @@ when isMainModule:
|
||||
const test1 = "abc\L+def xyz"
|
||||
assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
|
||||
assert UrlDecode(UrlEncode(test1)) == test1
|
||||
|
||||
|
||||
@@ -956,17 +956,37 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
if crename(source, dest) != 0'i32:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
when not defined(ENOENT):
|
||||
when not defined(ENOENT) and not defined(Windows):
|
||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
template DeleteFile(file: expr): expr {.immediate.} = DeleteFileW(file)
|
||||
template SetFileAttributes(file, attrs: expr): expr {.immediate.} =
|
||||
SetFileAttributesW(file, attrs)
|
||||
else:
|
||||
template DeleteFile(file: expr): expr {.immediate.} = DeleteFileA(file)
|
||||
template SetFileAttributes(file, attrs: expr): expr {.immediate.} =
|
||||
SetFileAttributesA(file, attrs)
|
||||
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
||||
## if the file never existed in the first place.
|
||||
## On Windows, ignores the read-only attribute.
|
||||
when defined(Windows):
|
||||
setFilePermissions(file, {fpUserWrite})
|
||||
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
when useWinUnicode:
|
||||
let f = newWideCString(file)
|
||||
else:
|
||||
let f = file
|
||||
if DeleteFile(f) == 0:
|
||||
if GetLastError() == ERROR_ACCESS_DENIED:
|
||||
if SetFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
|
||||
OSError(OSLastError())
|
||||
if DeleteFile(f) == 0:
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||
tags: [FExecIO].} =
|
||||
|
||||
@@ -41,6 +41,58 @@ type
|
||||
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
|
||||
poParentStreams ## use the parent's streams
|
||||
|
||||
proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to Windows API.
|
||||
## Based on Python's subprocess.list2cmdline
|
||||
## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
let needQuote = {' ', '\t'} in s or s.len == 0
|
||||
|
||||
result = ""
|
||||
var backslashBuff = ""
|
||||
if needQuote:
|
||||
result.add("\"")
|
||||
|
||||
for c in s:
|
||||
if c == '\\':
|
||||
backslashBuff.add(c)
|
||||
elif c == '\"':
|
||||
result.add(backslashBuff)
|
||||
result.add(backslashBuff)
|
||||
backslashBuff.setLen(0)
|
||||
result.add("\\\"")
|
||||
else:
|
||||
if backslashBuff.len != 0:
|
||||
result.add(backslashBuff)
|
||||
backslashBuff.setLen(0)
|
||||
result.add(c)
|
||||
|
||||
if needQuote:
|
||||
result.add("\"")
|
||||
|
||||
proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to POSIX shell.
|
||||
## Based on Python's pipes.quote
|
||||
const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
|
||||
'0'..'9', 'A'..'Z', 'a'..'z'}
|
||||
if s.len == 0:
|
||||
return "''"
|
||||
|
||||
let safe = s.allCharsInSet(safeUnixChars)
|
||||
|
||||
if safe:
|
||||
return s
|
||||
else:
|
||||
return "'" & s.replace("'", "'\"'\"'") & "'"
|
||||
|
||||
proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to shell.
|
||||
when defined(Windows):
|
||||
return quoteShellWindows(s)
|
||||
elif defined(posix):
|
||||
return quoteShellPosix(s)
|
||||
else:
|
||||
{.error:"quoteShell is not supported on your system".}
|
||||
|
||||
proc execProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): TaintedString {.
|
||||
@@ -307,10 +359,10 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
result.writeDataImpl = hsWriteData
|
||||
|
||||
proc buildCommandLine(a: string, args: openarray[string]): cstring =
|
||||
var res = quoteIfContainsWhite(a)
|
||||
var res = quoteShell(a)
|
||||
for i in 0..high(args):
|
||||
res.add(' ')
|
||||
res.add(quoteIfContainsWhite(args[i]))
|
||||
res.add(quoteShell(args[i]))
|
||||
result = cast[cstring](alloc0(res.len+1))
|
||||
copyMem(result, cstring(res), res.len)
|
||||
|
||||
@@ -510,10 +562,10 @@ elif not defined(useNimRtl):
|
||||
writeIdx = 1
|
||||
|
||||
proc addCmdArgs(command: string, args: openarray[string]): string =
|
||||
result = quoteIfContainsWhite(command)
|
||||
result = quoteShell(command)
|
||||
for i in 0 .. high(args):
|
||||
add(result, " ")
|
||||
add(result, quoteIfContainsWhite(args[i]))
|
||||
add(result, quoteShell(args[i]))
|
||||
|
||||
proc toCStringArray(b, a: openarray[string]): cstringArray =
|
||||
result = cast[cstringArray](alloc0((a.len + b.len + 1) * sizeof(cstring)))
|
||||
@@ -792,5 +844,14 @@ proc execCmdEx*(command: string, options: set[TProcessOption] = {
|
||||
close(p)
|
||||
|
||||
when isMainModule:
|
||||
var x = execProcess("gcc -v")
|
||||
echo "ECHO ", x
|
||||
assert quoteShellWindows("aaa") == "aaa"
|
||||
assert quoteShellWindows("aaa\"") == "aaa\\\""
|
||||
assert quoteShellWindows("") == "\"\""
|
||||
|
||||
assert quoteShellPosix("aaa") == "aaa"
|
||||
assert quoteShellPosix("aaa a") == "'aaa a'"
|
||||
assert quoteShellPosix("") == "''"
|
||||
assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
|
||||
|
||||
when defined(posix):
|
||||
assert quoteShell("") == "''"
|
||||
|
||||
@@ -709,9 +709,11 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
|
||||
if result != -1: return
|
||||
return -1
|
||||
|
||||
proc quoteIfContainsWhite*(s: string): string =
|
||||
proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||
## returns ``'"' & s & '"'`` if `s` contains a space and does not
|
||||
## start with a quote, else returns `s`
|
||||
## DEPRECATED as it was confused for shell quoting function.
|
||||
## For this application use osproc.quoteShell.
|
||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
|
||||
result = '"' & s & '"'
|
||||
else:
|
||||
|
||||
@@ -923,6 +923,10 @@ proc quit*(errorcode: int = QuitSuccess) {.
|
||||
## The proc ``quit(QuitSuccess)`` is called implicitly when your nimrod
|
||||
## program finishes without incident. A raised unhandled exception is
|
||||
## equivalent to calling ``quit(QuitFailure)``.
|
||||
##
|
||||
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
|
||||
## have any compile time effect. If you need to stop the compiler inside a
|
||||
## macro, use the ``error`` or ``fatal`` pragmas.
|
||||
|
||||
template sysAssert(cond: bool, msg: string) =
|
||||
when defined(useSysAssert):
|
||||
@@ -1947,15 +1951,13 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||
## The standard output stream.
|
||||
stderr* {.importc: "stderr", header: "<stdio.h>".}: TFile
|
||||
## The standard error stream.
|
||||
##
|
||||
## Note: In my opinion, this should not be used -- the concept of a
|
||||
## separate error stream is a design flaw of UNIX. A separate *message
|
||||
## stream* is a good idea, but since it is named ``stderr`` there are few
|
||||
## programs out there that distinguish properly between ``stdout`` and
|
||||
## ``stderr``. So, that's what you get if you don't name your variables
|
||||
## appropriately. It also annoys people if redirection
|
||||
## via ``>output.txt`` does not work because the program writes
|
||||
## to ``stderr``.
|
||||
|
||||
when defined(useStdoutAsStdmsg):
|
||||
template stdmsg*: TFile = stdout
|
||||
else:
|
||||
template stdmsg*: TFile = stderr
|
||||
## Template which expands to either stdout or stderr depending on
|
||||
## `useStdoutAsStdmsg` compile-time switch.
|
||||
|
||||
proc Open*(f: var TFile, filename: string,
|
||||
mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].}
|
||||
|
||||
@@ -760,7 +760,7 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
|
||||
# ---------------------- thread memory region -------------------------------
|
||||
|
||||
template InstantiateForRegion(allocator: expr) =
|
||||
when false:
|
||||
when defined(fulldebug):
|
||||
proc interiorAllocatedPtr*(p: pointer): pointer =
|
||||
result = interiorAllocatedPtr(allocator, p)
|
||||
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
# use the heap (and nor exceptions) do not include the GC or memory allocator.
|
||||
|
||||
var
|
||||
stackTraceNewLine*: string ## undocumented feature; it is replaced by ``<br>``
|
||||
## for CGI applications
|
||||
|
||||
template stackTraceNL: expr =
|
||||
(if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
|
||||
errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
|
||||
## Function that will be called
|
||||
## instead of stdmsg.write when printing stacktrace.
|
||||
## Unstable API.
|
||||
|
||||
when not defined(windows) or not defined(guiapp):
|
||||
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
||||
proc writeToStdErr(msg: CString) = write(stdmsg, msg)
|
||||
|
||||
else:
|
||||
proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
|
||||
@@ -27,6 +26,12 @@ else:
|
||||
proc writeToStdErr(msg: CString) =
|
||||
discard MessageBoxA(0, msg, nil, 0)
|
||||
|
||||
proc showErrorMessage(data: cstring) =
|
||||
if errorMessageWriter != nil:
|
||||
errorMessageWriter($data)
|
||||
else:
|
||||
writeToStdErr(data)
|
||||
|
||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
|
||||
proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
|
||||
@@ -111,7 +116,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||
add(s, tempDlInfo.dli_sname)
|
||||
else:
|
||||
add(s, '?')
|
||||
add(s, stackTraceNL)
|
||||
add(s, "\n")
|
||||
else:
|
||||
if dlresult != 0 and tempDlInfo.dli_sname != nil and
|
||||
c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
|
||||
@@ -172,21 +177,18 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
add(s, ')')
|
||||
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
||||
add(s, tempFrames[j].procname)
|
||||
add(s, stackTraceNL)
|
||||
add(s, "\n")
|
||||
|
||||
when hasSomeStackTrace:
|
||||
proc rawWriteStackTrace(s: var string) =
|
||||
when nimrodStackTrace:
|
||||
if framePtr == nil:
|
||||
add(s, "No stack traceback available")
|
||||
add(s, stackTraceNL)
|
||||
add(s, "No stack traceback available\n")
|
||||
else:
|
||||
add(s, "Traceback (most recent call last)")
|
||||
add(s, stackTraceNL)
|
||||
add(s, "Traceback (most recent call last)\n")
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
elif defined(nativeStackTrace) and nativeStackTraceSupported:
|
||||
add(s, "Traceback from system (most recent call last)")
|
||||
add(s, stackTraceNL)
|
||||
add(s, "Traceback from system (most recent call last)\n")
|
||||
auxWriteStackTraceWithBacktrace(s)
|
||||
else:
|
||||
add(s, "No stack traceback available\n")
|
||||
@@ -207,7 +209,7 @@ proc raiseExceptionAux(e: ref E_Base) =
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
elif e[] of EOutOfMemory:
|
||||
writeToStdErr(e.name)
|
||||
showErrorMessage(e.name)
|
||||
quitOrDebug()
|
||||
else:
|
||||
when hasSomeStackTrace:
|
||||
@@ -219,7 +221,7 @@ proc raiseExceptionAux(e: ref E_Base) =
|
||||
add(buf, " [")
|
||||
add(buf, $e.name)
|
||||
add(buf, "]\n")
|
||||
writeToStdErr(buf)
|
||||
showErrorMessage(buf)
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen: expr) =
|
||||
@@ -235,7 +237,7 @@ proc raiseExceptionAux(e: ref E_Base) =
|
||||
add(buf, " [")
|
||||
xadd(buf, e.name, c_strlen(e.name))
|
||||
add(buf, "]\n")
|
||||
writeToStdErr(buf)
|
||||
showErrorMessage(buf)
|
||||
quitOrDebug()
|
||||
|
||||
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||
@@ -255,9 +257,9 @@ proc WriteStackTrace() =
|
||||
when hasSomeStackTrace:
|
||||
var s = ""
|
||||
rawWriteStackTrace(s)
|
||||
writeToStdErr(s)
|
||||
showErrorMessage(s)
|
||||
else:
|
||||
writeToStdErr("No stack traceback available\n")
|
||||
showErrorMessage("No stack traceback available\n")
|
||||
|
||||
proc getStackTrace(): string =
|
||||
when hasSomeStackTrace:
|
||||
@@ -298,13 +300,13 @@ when not defined(noSignalHandler):
|
||||
var buf = newStringOfCap(2000)
|
||||
rawWriteStackTrace(buf)
|
||||
processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
|
||||
writeToStdErr(buf)
|
||||
showErrorMessage(buf)
|
||||
GC_enable()
|
||||
else:
|
||||
var msg: cstring
|
||||
template asgn(y: expr) = msg = y
|
||||
processSignal(sig, asgn)
|
||||
writeToStdErr(msg)
|
||||
showErrorMessage(msg)
|
||||
when defined(endb): dbgAborting = True
|
||||
quit(1) # always quit when SIGABRT
|
||||
|
||||
|
||||
@@ -345,8 +345,9 @@ proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
|
||||
|
||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||
gcAssert(cell != nil, "forAllChildren: 1")
|
||||
gcAssert(cell.typ != nil, "forAllChildren: 2")
|
||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
||||
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
|
||||
let marker = cell.typ.marker
|
||||
if marker != nil:
|
||||
marker(cellToUsr(cell), op.int)
|
||||
@@ -361,7 +362,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||
for i in 0..s.len-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||
GenericSeqSize), cell.typ.base, op)
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||
@@ -408,8 +409,10 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||
add(gch.zct, res)
|
||||
|
||||
{.push stackTrace: off, profiler:off.}
|
||||
proc gcInvariant*(msg: string) =
|
||||
sysAssert(allocInv(gch.region), msg)
|
||||
proc gcInvariant*() =
|
||||
sysAssert(allocInv(gch.region), "injected")
|
||||
when defined(markForDebug):
|
||||
markForDebug(gch)
|
||||
{.pop.}
|
||||
|
||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
||||
|
||||
@@ -18,7 +18,8 @@ const
|
||||
logGC = false
|
||||
traceGC = false # extensive debugging
|
||||
alwaysCycleGC = false
|
||||
alwaysGC = false # collect after every memory allocation (for debugging)
|
||||
alwaysGC = defined(fulldebug) # collect after every memory
|
||||
# allocation (for debugging)
|
||||
leakDetector = false
|
||||
overwriteFree = false
|
||||
trackAllocationSource = leakDetector
|
||||
|
||||
@@ -416,17 +416,17 @@ var
|
||||
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
||||
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
|
||||
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
|
||||
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
|
||||
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
|
||||
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
|
||||
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
|
||||
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
|
||||
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
|
||||
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
|
||||
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
|
||||
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
|
||||
|
||||
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
|
||||
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
|
||||
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
|
||||
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
|
||||
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
|
||||
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
|
||||
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
|
||||
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
|
||||
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
|
||||
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
|
||||
|
||||
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
|
||||
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
|
||||
|
||||
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
|
||||
@@ -553,18 +553,26 @@ const
|
||||
|
||||
FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
|
||||
|
||||
# Error Constants
|
||||
const
|
||||
ERROR_ACCESS_DENIED* = 5
|
||||
|
||||
when useWinUnicode:
|
||||
proc CreateFileW*(lpFileName: widecstring, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: THANDLE): THANDLE {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
|
||||
proc DeleteFileW*(pathName: widecstring): int32 {.
|
||||
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
|
||||
else:
|
||||
proc CreateFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: THANDLE): THANDLE {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileA".}
|
||||
proc DeleteFileA*(pathName: cstring): int32 {.
|
||||
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
|
||||
|
||||
proc SetEndOfFile*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "SetEndOfFile".}
|
||||
|
||||
@@ -14,7 +14,7 @@ when haveZipLib:
|
||||
import zipfiles
|
||||
|
||||
import
|
||||
os, strutils, parseopt, parsecfg, strtabs, streams, debcreation
|
||||
os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation
|
||||
|
||||
const
|
||||
maxOS = 20 # max number of OSes
|
||||
@@ -486,7 +486,7 @@ proc setupDist(c: var TConfigData) =
|
||||
if c.innoSetup.path.len == 0:
|
||||
c.innoSetup.path = "iscc.exe"
|
||||
var outcmd = if c.outdir.len == 0: "build" else: c.outdir
|
||||
var cmd = "$# $# /O$# $#" % [quoteIfContainsWhite(c.innoSetup.path),
|
||||
var cmd = "$# $# /O$# $#" % [quoteShell(c.innoSetup.path),
|
||||
c.innoSetup.flags, outcmd, n]
|
||||
echo(cmd)
|
||||
if execShellCmd(cmd) == 0:
|
||||
@@ -587,4 +587,3 @@ if actionZip in c.actions:
|
||||
quit("libzip is not installed")
|
||||
if actionDeb in c.actions:
|
||||
debDist(c)
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ Changes affecting backwards compatibility
|
||||
require an error code to be passed to them. This error code can be retrieved
|
||||
using the new ``OSLastError`` proc.
|
||||
- ``os.parentDir`` now returns "" if there is no parent dir.
|
||||
|
||||
- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
|
||||
is used.
|
||||
|
||||
Compiler Additions
|
||||
------------------
|
||||
|
||||
Reference in New Issue
Block a user