Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Conflicts: lib/pure/osproc.nim
This commit is contained in:
commit
e0e0b409e4
64 changed files with 1141 additions and 574 deletions
|
|
@ -336,26 +336,52 @@ type
|
||||||
tyConst, tyMutable, tyVarargs,
|
tyConst, tyMutable, tyVarargs,
|
||||||
tyIter, # unused
|
tyIter, # unused
|
||||||
tyProxy # used as errornous type (for idetools)
|
tyProxy # used as errornous type (for idetools)
|
||||||
tyTypeClass
|
|
||||||
tyParametricTypeClass # structured similarly to tyGenericInst
|
|
||||||
# lastSon is the body of the type class
|
|
||||||
|
|
||||||
tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc
|
tyBuiltInTypeClass #\
|
||||||
|
# Type such as the catch-all object, tuple, seq, etc
|
||||||
|
|
||||||
tyCompositeTypeClass #
|
tyUserTypeClass #\
|
||||||
|
# the body of a user-defined type class
|
||||||
|
|
||||||
tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`,
|
tyUserTypeClassInst #\
|
||||||
# `Sortable and Enumable`, etc
|
# Instance of a parametric user-defined type class.
|
||||||
|
# Structured similarly to tyGenericInst.
|
||||||
|
# tyGenericInst represents concrete types, while
|
||||||
|
# this is still a "generic param" that will bind types
|
||||||
|
# and resolves them during sigmatch and instantiation.
|
||||||
|
|
||||||
tyAnything # a type class matching any type
|
tyCompositeTypeClass #\
|
||||||
|
# Type such as seq[Number]
|
||||||
|
# The notes for tyUserTypeClassInst apply here as well
|
||||||
|
# sons[0]: the original expression used by the user.
|
||||||
|
# sons[1]: fully expanded and instantiated meta type
|
||||||
|
# (potentially following aliases)
|
||||||
|
|
||||||
tyStatic # a value known at compile type (the underlying type is .base)
|
tyAnd, tyOr, tyNot #\
|
||||||
|
# boolean type classes such as `string|int`,`not seq`,
|
||||||
|
# `Sortable and Enumable`, etc
|
||||||
|
|
||||||
tyFromExpr # This is a type representing an expression that depends
|
tyAnything #\
|
||||||
# on generic parameters (the exprsesion is stored in t.n)
|
# a type class matching any type
|
||||||
# It will be converted to a real type only during generic
|
|
||||||
# instantiation and prior to this it has the potential to
|
tyStatic #\
|
||||||
# be any type.
|
# a value known at compile type (the underlying type is .base)
|
||||||
|
|
||||||
|
tyFromExpr #\
|
||||||
|
# This is a type representing an expression that depends
|
||||||
|
# on generic parameters (the exprsesion is stored in t.n)
|
||||||
|
# It will be converted to a real type only during generic
|
||||||
|
# instantiation and prior to this it has the potential to
|
||||||
|
# be any type.
|
||||||
|
|
||||||
|
tyFieldAccessor #\
|
||||||
|
# Expressions such as Type.field (valid in contexts such
|
||||||
|
# as the `is` operator and magics like `high` and `low`).
|
||||||
|
# Could be lifted to a single argument proc returning the
|
||||||
|
# field value.
|
||||||
|
# sons[0]: type of containing object or tuple
|
||||||
|
# sons[1]: field type
|
||||||
|
# .n: nkDotExpr storing the field name
|
||||||
|
|
||||||
const
|
const
|
||||||
tyPureObject* = tyTuple
|
tyPureObject* = tyTuple
|
||||||
|
|
@ -364,8 +390,9 @@ const
|
||||||
|
|
||||||
tyUnknownTypes* = {tyError, tyFromExpr}
|
tyUnknownTypes* = {tyError, tyFromExpr}
|
||||||
|
|
||||||
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
|
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||||
tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
|
tyUserTypeClass, tyUserTypeClassInst,
|
||||||
|
tyAnd, tyOr, tyNot, tyAnything}
|
||||||
|
|
||||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
|
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
proc addComma(r: PRope): PRope =
|
proc addComma(r: PRope): PRope =
|
||||||
result = if r == nil: r else: con(r, ~", ")
|
result = if r == nil: r else: con(r, ~", ")
|
||||||
|
|
||||||
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
|
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
|
||||||
|
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
|
||||||
var op: TLoc
|
var op: TLoc
|
||||||
initLocExpr(p, ri.sons[0], op)
|
initLocExpr(p, ri.sons[0], op)
|
||||||
var pl: PRope
|
var pl: PRope
|
||||||
|
|
@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
if i < length - 1: app(pl, ~", ")
|
if i < length - 1: app(pl, ~", ")
|
||||||
|
|
||||||
template genCallPattern {.dirty.} =
|
template genCallPattern {.dirty.} =
|
||||||
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||||
|
|
||||||
let rawProc = getRawProcType(p, typ)
|
let rawProc = getRawProcType(p, typ)
|
||||||
|
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
|
||||||
if typ.sons[0] != nil:
|
if typ.sons[0] != nil:
|
||||||
if isInvalidReturnType(typ.sons[0]):
|
if isInvalidReturnType(typ.sons[0]):
|
||||||
if sonsLen(ri) > 1: app(pl, ~", ")
|
if sonsLen(ri) > 1: app(pl, ~", ")
|
||||||
|
|
@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
assert(d.t != nil) # generate an assignment to d:
|
assert(d.t != nil) # generate an assignment to d:
|
||||||
var list: TLoc
|
var list: TLoc
|
||||||
initLoc(list, locCall, d.t, OnUnknown)
|
initLoc(list, locCall, d.t, OnUnknown)
|
||||||
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
|
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
|
||||||
genAssignment(p, d, list, {}) # no need for deep copying
|
genAssignment(p, d, list, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
genCallPattern()
|
genCallPattern()
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
gCanonicalTypes[k] = key
|
gCanonicalTypes[k] = key
|
||||||
result = key
|
result = key
|
||||||
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
||||||
tyFromExpr, tyStatic:
|
tyFromExpr, tyStatic, tyFieldAccessor:
|
||||||
internalError("GetUniqueType")
|
internalError("GetUniqueType")
|
||||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
||||||
result = getUniqueType(lastSon(key))
|
result = getUniqueType(lastSon(key))
|
||||||
|
|
|
||||||
|
|
@ -913,21 +913,21 @@ proc addIntTypes(result: var PRope) {.inline.} =
|
||||||
|
|
||||||
proc getCopyright(cfilenoext: string): PRope =
|
proc getCopyright(cfilenoext: string): PRope =
|
||||||
if optCompileOnly in gGlobalOptions:
|
if optCompileOnly in gGlobalOptions:
|
||||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||||
"/* (c) 2014 Andreas Rumpf */$n" &
|
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||||
"/* The generated code is subject to the original license. */$n",
|
"/* The generated code is subject to the original license. */$N",
|
||||||
"; Generated by Nimrod Compiler v$1$n" &
|
"; Generated by Nimrod Compiler v$1$N" &
|
||||||
"; (c) 2012 Andreas Rumpf$n", [toRope(VersionAsString)])
|
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
||||||
else:
|
else:
|
||||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||||
"/* (c) 2014 Andreas Rumpf */$n" &
|
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||||
"/* The generated code is subject to the original license. */$n" &
|
"/* The generated code is subject to the original license. */$N" &
|
||||||
"/* Compiled for: $2, $3, $4 */$n" &
|
"/* Compiled for: $2, $3, $4 */$N" &
|
||||||
"/* Command for C compiler:$n $5 */$n",
|
"/* Command for C compiler:$n $5 */$N",
|
||||||
"; Generated by Nimrod Compiler v$1$n" &
|
"; Generated by Nimrod Compiler v$1$N" &
|
||||||
"; (c) 2014 Andreas Rumpf$n" &
|
"; (c) 2014 Andreas Rumpf$N" &
|
||||||
"; Compiled for: $2, $3, $4$n" &
|
"; Compiled for: $2, $3, $4$N" &
|
||||||
"; Command for LLVM compiler:$n $5$n", [toRope(VersionAsString),
|
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
||||||
toRope(platform.OS[targetOS].name),
|
toRope(platform.OS[targetOS].name),
|
||||||
toRope(platform.CPU[targetCPU].name),
|
toRope(platform.CPU[targetCPU].name),
|
||||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||||
|
|
@ -941,61 +941,71 @@ proc genFilenames(m: BModule): PRope =
|
||||||
discard cgsym(m, "dbgRegisterFilename")
|
discard cgsym(m, "dbgRegisterFilename")
|
||||||
result = nil
|
result = nil
|
||||||
for i in 0.. <fileInfos.len:
|
for i in 0.. <fileInfos.len:
|
||||||
result.appf("dbgRegisterFilename($1);$n", fileInfos[i].projPath.makeCString)
|
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
|
||||||
|
|
||||||
proc genMainProc(m: BModule) =
|
proc genMainProc(m: BModule) =
|
||||||
const
|
const
|
||||||
PreMainBody =
|
PreMainBody =
|
||||||
"\tsystemDatInit();$n" &
|
"\tsystemDatInit();$N" &
|
||||||
"\tsystemInit();$n" &
|
"\tsystemInit();$N" &
|
||||||
"$1" &
|
"$1" &
|
||||||
"$2" &
|
"$2" &
|
||||||
"$3" &
|
"$3" &
|
||||||
"$4"
|
"$4"
|
||||||
|
|
||||||
MainProcs =
|
MainProcs =
|
||||||
"\tPreMain();$n" &
|
"\tNimMain();$N"
|
||||||
"\tNimMain();$n"
|
|
||||||
|
|
||||||
MainProcsWithResult =
|
MainProcsWithResult =
|
||||||
MainProcs & "\treturn nim_program_result;$n"
|
MainProcs & "\treturn nim_program_result;$N"
|
||||||
|
|
||||||
|
NimMainBody =
|
||||||
|
"N_CDECL(void, NimMain)(void) {$N" &
|
||||||
|
"\tPreMain();$N" &
|
||||||
|
"$1$N" &
|
||||||
|
"}$N"
|
||||||
|
|
||||||
PosixNimMain =
|
PosixNimMain =
|
||||||
"int cmdCount;$n" &
|
"int cmdCount;$N" &
|
||||||
"char** cmdLine;$n" &
|
"char** cmdLine;$N" &
|
||||||
"char** gEnv;$n" &
|
"char** gEnv;$N" &
|
||||||
"N_CDECL(void, NimMain)(void) {$n$1}$n"
|
NimMainBody
|
||||||
|
|
||||||
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
|
PosixCMain =
|
||||||
"\tcmdLine = args;$n" & "\tcmdCount = argc;$n" & "\tgEnv = env;$n" &
|
"int main(int argc, char** args, char** env) {$N" &
|
||||||
MainProcsWithResult &
|
"\tcmdLine = args;$N" &
|
||||||
"}$n"
|
"\tcmdCount = argc;$N" &
|
||||||
|
"\tgEnv = env;$N" &
|
||||||
|
MainProcsWithResult &
|
||||||
|
"}$N"
|
||||||
|
|
||||||
StandaloneCMain = "int main(void) {$n" &
|
StandaloneCMain =
|
||||||
MainProcs &
|
"int main(void) {$N" &
|
||||||
"\treturn 0;$n" & "}$n"
|
MainProcs &
|
||||||
|
"\treturn 0;$N" &
|
||||||
|
"}$N"
|
||||||
|
|
||||||
WinNimMain = "N_CDECL(void, NimMain)(void) {$n$1}$n"
|
WinNimMain = NimMainBody
|
||||||
|
|
||||||
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
|
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
|
||||||
" HINSTANCE hPrevInstance, $n" &
|
" HINSTANCE hPrevInstance, $N" &
|
||||||
" LPSTR lpCmdLine, int nCmdShow) {$n" &
|
" LPSTR lpCmdLine, int nCmdShow) {$N" &
|
||||||
MainProcsWithResult & "}$n"
|
MainProcsWithResult & "}$N"
|
||||||
|
|
||||||
WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n$1}$n"
|
WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
|
||||||
|
|
||||||
WinCDllMain =
|
WinCDllMain =
|
||||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
|
||||||
" LPVOID lpvReserved) {$n" &
|
" LPVOID lpvReserved) {$N" &
|
||||||
"\tif(fwdreason == DLL_PROCESS_ATTACH) {" & MainProcs & "}$n" &
|
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
|
||||||
"\treturn 1;$n}$n"
|
"\treturn 1;$N}$N"
|
||||||
|
|
||||||
PosixNimDllMain = WinNimDllMain
|
PosixNimDllMain = WinNimDllMain
|
||||||
|
|
||||||
PosixCDllMain =
|
PosixCDllMain =
|
||||||
"void NIM_POSIX_INIT NimMainInit(void) {$n" &
|
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
|
||||||
MainProcs &
|
MainProcs &
|
||||||
"}$n"
|
"}$N"
|
||||||
|
|
||||||
var nimMain, otherMain: TFormatStr
|
var nimMain, otherMain: TFormatStr
|
||||||
if platform.targetOS == osWindows and
|
if platform.targetOS == osWindows and
|
||||||
|
|
@ -1022,9 +1032,9 @@ proc genMainProc(m: BModule) =
|
||||||
|
|
||||||
let initStackBottomCall = if emulatedThreadVars() or
|
let initStackBottomCall = if emulatedThreadVars() or
|
||||||
platform.targetOS == osStandalone: "".toRope
|
platform.targetOS == osStandalone: "".toRope
|
||||||
else: ropecg(m, "\t#initStackBottom();$n")
|
else: ropecg(m, "\t#initStackBottom();$N")
|
||||||
inc(m.labels)
|
inc(m.labels)
|
||||||
appcg(m, m.s[cfsProcs], "void PreMain() {$n" & PreMainBody & "}$n", [
|
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N", [
|
||||||
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
|
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
|
||||||
|
|
||||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
|
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
|
||||||
|
|
@ -1049,8 +1059,8 @@ proc registerModuleToMain(m: PSym) =
|
||||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
||||||
"declare void $1() noinline$N", [datInit])
|
"declare void $1() noinline$N", [datInit])
|
||||||
if sfSystemModule notin m.flags:
|
if sfSystemModule notin m.flags:
|
||||||
appff(mainDatInit, "\t$1();$n", "call void ()* $1$n", [datInit])
|
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
||||||
let initCall = ropeff("\t$1();$n", "call void ()* $1$n", [init])
|
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
|
||||||
if sfMainModule in m.flags:
|
if sfMainModule in m.flags:
|
||||||
app(mainModInit, initCall)
|
app(mainModInit, initCall)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1058,7 +1068,7 @@ proc registerModuleToMain(m: PSym) =
|
||||||
|
|
||||||
proc genInitCode(m: BModule) =
|
proc genInitCode(m: BModule) =
|
||||||
var initname = getInitName(m.module)
|
var initname = getInitName(m.module)
|
||||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
|
||||||
"define void $1() noinline {$n", [initname])
|
"define void $1() noinline {$n", [initname])
|
||||||
if m.typeNodes > 0:
|
if m.typeNodes > 0:
|
||||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||||
|
|
@ -1101,7 +1111,7 @@ proc genInitCode(m: BModule) =
|
||||||
app(prc, deinitGCFrame(m.initProc))
|
app(prc, deinitGCFrame(m.initProc))
|
||||||
appf(prc, "}$N$N")
|
appf(prc, "}$N$N")
|
||||||
|
|
||||||
prc.appff("N_NOINLINE(void, $1)(void) {$n",
|
prc.appff("N_NOINLINE(void, $1)(void) {$N",
|
||||||
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
||||||
|
|
||||||
for i in cfsTypeInit1..cfsDynLibInit:
|
for i in cfsTypeInit1..cfsDynLibInit:
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||||
result = etyObject
|
result = etyObject
|
||||||
of tyNil: result = etyNull
|
of tyNil: result = etyNull
|
||||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
|
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
|
||||||
tyNone, tyFromExpr, tyForward, tyEmpty,
|
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
||||||
result = etyNone
|
result = etyNone
|
||||||
of tyProc: result = etyProc
|
of tyProc: result = etyProc
|
||||||
|
|
|
||||||
|
|
@ -116,9 +116,9 @@ type
|
||||||
TDep = tuple[e: PEnv, field: PSym]
|
TDep = tuple[e: PEnv, field: PSym]
|
||||||
TEnv {.final.} = object of TObject
|
TEnv {.final.} = object of TObject
|
||||||
attachedNode: PNode
|
attachedNode: PNode
|
||||||
closure: PSym # if != nil it is a used environment
|
createdVar: PSym # if != nil it is a used environment
|
||||||
capturedVars: seq[PSym] # captured variables in this environment
|
capturedVars: seq[PSym] # captured variables in this environment
|
||||||
deps: seq[TDep] # dependencies
|
deps: seq[TDep] # dependencies
|
||||||
up: PEnv
|
up: PEnv
|
||||||
tup: PType
|
tup: PType
|
||||||
|
|
||||||
|
|
@ -130,12 +130,99 @@ type
|
||||||
TOuterContext {.final.} = object
|
TOuterContext {.final.} = object
|
||||||
fn: PSym # may also be a module!
|
fn: PSym # may also be a module!
|
||||||
currentEnv: PEnv
|
currentEnv: PEnv
|
||||||
|
isIter: bool # first class iterator?
|
||||||
capturedVars, processed: TIntSet
|
capturedVars, processed: TIntSet
|
||||||
localsToEnv: TIdTable # PSym->PEnv mapping
|
localsToEnv: TIdTable # PSym->PEnv mapping
|
||||||
localsToAccess: TIdNodeTable
|
localsToAccess: TIdNodeTable
|
||||||
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
||||||
up: POuterContext
|
up: POuterContext
|
||||||
|
|
||||||
|
closureParam, state, resultSym: PSym # only if isIter
|
||||||
|
tup: PType # only if isIter
|
||||||
|
|
||||||
|
|
||||||
|
proc getStateType(iter: PSym): PType =
|
||||||
|
var n = newNodeI(nkRange, iter.info)
|
||||||
|
addSon(n, newIntNode(nkIntLit, -1))
|
||||||
|
addSon(n, newIntNode(nkIntLit, 0))
|
||||||
|
result = newType(tyRange, iter)
|
||||||
|
result.n = n
|
||||||
|
rawAddSon(result, getSysType(tyInt))
|
||||||
|
|
||||||
|
proc createStateField(iter: PSym): PSym =
|
||||||
|
result = newSym(skField, getIdent(":state"), iter, iter.info)
|
||||||
|
result.typ = getStateType(iter)
|
||||||
|
|
||||||
|
proc newIterResult(iter: PSym): PSym =
|
||||||
|
if resultPos < iter.ast.len:
|
||||||
|
result = iter.ast.sons[resultPos].sym
|
||||||
|
else:
|
||||||
|
# XXX a bit hacky:
|
||||||
|
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||||
|
result.typ = iter.typ.sons[0]
|
||||||
|
incl(result.flags, sfUsed)
|
||||||
|
iter.ast.add newSymNode(result)
|
||||||
|
|
||||||
|
proc addHiddenParam(routine: PSym, param: PSym) =
|
||||||
|
var params = routine.ast.sons[paramsPos]
|
||||||
|
# -1 is correct here as param.position is 0 based but we have at position 0
|
||||||
|
# some nkEffect node:
|
||||||
|
param.position = params.len-1
|
||||||
|
addSon(params, newSymNode(param))
|
||||||
|
incl(routine.typ.flags, tfCapturesEnv)
|
||||||
|
#echo "produced environment: ", param.id, " for ", routine.name.s
|
||||||
|
|
||||||
|
proc getHiddenParam(routine: PSym): PSym =
|
||||||
|
let params = routine.ast.sons[paramsPos]
|
||||||
|
let hidden = lastSon(params)
|
||||||
|
assert hidden.kind == nkSym
|
||||||
|
result = hidden.sym
|
||||||
|
|
||||||
|
proc getEnvParam(routine: PSym): PSym =
|
||||||
|
let params = routine.ast.sons[paramsPos]
|
||||||
|
let hidden = lastSon(params)
|
||||||
|
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||||
|
result = hidden.sym
|
||||||
|
|
||||||
|
proc addField(tup: PType, s: PSym) =
|
||||||
|
var field = newSym(skField, s.name, s.owner, s.info)
|
||||||
|
let t = skipIntLit(s.typ)
|
||||||
|
field.typ = t
|
||||||
|
field.position = sonsLen(tup)
|
||||||
|
addSon(tup.n, newSymNode(field))
|
||||||
|
rawAddSon(tup, t)
|
||||||
|
|
||||||
|
proc initIterContext(c: POuterContext, iter: PSym) =
|
||||||
|
c.fn = iter
|
||||||
|
c.capturedVars = initIntSet()
|
||||||
|
|
||||||
|
var cp = getEnvParam(iter)
|
||||||
|
if cp == nil:
|
||||||
|
c.tup = newType(tyTuple, iter)
|
||||||
|
c.tup.n = newNodeI(nkRecList, iter.info)
|
||||||
|
|
||||||
|
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
||||||
|
incl(cp.flags, sfFromGeneric)
|
||||||
|
cp.typ = newType(tyRef, iter)
|
||||||
|
rawAddSon(cp.typ, c.tup)
|
||||||
|
addHiddenParam(iter, cp)
|
||||||
|
|
||||||
|
c.state = createStateField(iter)
|
||||||
|
addField(c.tup, c.state)
|
||||||
|
else:
|
||||||
|
c.tup = cp.typ.sons[0]
|
||||||
|
assert c.tup.kind == tyTuple
|
||||||
|
if c.tup.len > 0:
|
||||||
|
c.state = c.tup.n[0].sym
|
||||||
|
else:
|
||||||
|
c.state = createStateField(iter)
|
||||||
|
addField(c.tup, c.state)
|
||||||
|
|
||||||
|
c.closureParam = cp
|
||||||
|
if iter.typ.sons[0] != nil:
|
||||||
|
c.resultSym = newIterResult(iter)
|
||||||
|
#iter.ast.add(newSymNode(c.resultSym))
|
||||||
|
|
||||||
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
|
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
|
||||||
new(result)
|
new(result)
|
||||||
result.fn = fn
|
result.fn = fn
|
||||||
|
|
@ -144,6 +231,8 @@ proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
|
||||||
initIdNodeTable(result.localsToAccess)
|
initIdNodeTable(result.localsToAccess)
|
||||||
initIdTable(result.localsToEnv)
|
initIdTable(result.localsToEnv)
|
||||||
initIdTable(result.lambdasToEnv)
|
initIdTable(result.lambdasToEnv)
|
||||||
|
result.isIter = fn.kind == skIterator and fn.typ.callConv == ccClosure
|
||||||
|
if result.isIter: initIterContext(result, fn)
|
||||||
|
|
||||||
proc newInnerContext(fn: PSym): PInnerContext =
|
proc newInnerContext(fn: PSym): PInnerContext =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -159,17 +248,12 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
|
||||||
result.up = up
|
result.up = up
|
||||||
result.attachedNode = n
|
result.attachedNode = n
|
||||||
|
|
||||||
proc addField(tup: PType, s: PSym) =
|
|
||||||
var field = newSym(skField, s.name, s.owner, s.info)
|
|
||||||
let t = skipIntLit(s.typ)
|
|
||||||
field.typ = t
|
|
||||||
field.position = sonsLen(tup)
|
|
||||||
addSon(tup.n, newSymNode(field))
|
|
||||||
rawAddSon(tup, t)
|
|
||||||
|
|
||||||
proc addCapturedVar(e: PEnv, v: PSym) =
|
proc addCapturedVar(e: PEnv, v: PSym) =
|
||||||
for x in e.capturedVars:
|
for x in e.capturedVars:
|
||||||
if x == v: return
|
if x == v: return
|
||||||
|
# XXX meh, just add the state field for every closure for now, it's too
|
||||||
|
# hard to figure out if it comes from a closure iterator:
|
||||||
|
if e.tup.len == 0: addField(e.tup, createStateField(v.owner))
|
||||||
e.capturedVars.add(v)
|
e.capturedVars.add(v)
|
||||||
addField(e.tup, v)
|
addField(e.tup, v)
|
||||||
|
|
||||||
|
|
@ -189,6 +273,7 @@ proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||||
# returns a[].b as a node
|
# returns a[].b as a node
|
||||||
var deref = newNodeI(nkHiddenDeref, info)
|
var deref = newNodeI(nkHiddenDeref, info)
|
||||||
deref.typ = a.typ.sons[0]
|
deref.typ = a.typ.sons[0]
|
||||||
|
assert deref.typ.kind == tyTuple
|
||||||
let field = getSymFromList(deref.typ.n, b.name)
|
let field = getSymFromList(deref.typ.n, b.name)
|
||||||
assert field != nil, b.name.s
|
assert field != nil, b.name.s
|
||||||
addSon(deref, a)
|
addSon(deref, a)
|
||||||
|
|
@ -205,33 +290,24 @@ proc newCall(a, b: PSym): PNode =
|
||||||
result.add newSymNode(a)
|
result.add newSymNode(a)
|
||||||
result.add newSymNode(b)
|
result.add newSymNode(b)
|
||||||
|
|
||||||
proc addHiddenParam(routine: PSym, param: PSym) =
|
|
||||||
var params = routine.ast.sons[paramsPos]
|
|
||||||
# -1 is correct here as param.position is 0 based but we have at position 0
|
|
||||||
# some nkEffect node:
|
|
||||||
param.position = params.len-1
|
|
||||||
addSon(params, newSymNode(param))
|
|
||||||
incl(routine.typ.flags, tfCapturesEnv)
|
|
||||||
#echo "produced environment: ", param.id, " for ", routine.name.s
|
|
||||||
|
|
||||||
proc getHiddenParam(routine: PSym): PSym =
|
|
||||||
let params = routine.ast.sons[paramsPos]
|
|
||||||
let hidden = lastSon(params)
|
|
||||||
assert hidden.kind == nkSym
|
|
||||||
result = hidden.sym
|
|
||||||
|
|
||||||
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
|
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
|
||||||
result = s.kind in {skProc, skMethod, skConverter} and
|
result = (s.kind in {skProc, skMethod, skConverter} or
|
||||||
|
s.kind == skIterator and s.typ.callConv == ccClosure) and
|
||||||
s.skipGenericOwner == outerProc
|
s.skipGenericOwner == outerProc
|
||||||
#s.typ.callConv == ccClosure
|
#s.typ.callConv == ccClosure
|
||||||
|
|
||||||
proc addClosureParam(i: PInnerContext, e: PEnv) =
|
proc addClosureParam(i: PInnerContext, e: PEnv) =
|
||||||
var cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
|
var cp = getEnvParam(i.fn)
|
||||||
incl(cp.flags, sfFromGeneric)
|
if cp == nil:
|
||||||
cp.typ = newType(tyRef, i.fn)
|
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
|
||||||
rawAddSon(cp.typ, e.tup)
|
incl(cp.flags, sfFromGeneric)
|
||||||
|
cp.typ = newType(tyRef, i.fn)
|
||||||
|
rawAddSon(cp.typ, e.tup)
|
||||||
|
addHiddenParam(i.fn, cp)
|
||||||
|
else:
|
||||||
|
e.tup = cp.typ.sons[0]
|
||||||
|
assert e.tup.kind == tyTuple
|
||||||
i.closureParam = cp
|
i.closureParam = cp
|
||||||
addHiddenParam(i.fn, i.closureParam)
|
|
||||||
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
|
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
|
||||||
|
|
||||||
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
|
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
|
||||||
|
|
@ -306,7 +382,9 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
|
||||||
var s = n.sym
|
var s = n.sym
|
||||||
if interestingVar(s) and i.fn.id != s.owner.id:
|
if interestingVar(s) and i.fn.id != s.owner.id:
|
||||||
captureVar(o, i, s, n.info)
|
captureVar(o, i, s, n.info)
|
||||||
elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
|
elif s.kind in {skProc, skMethod, skConverter} and
|
||||||
|
s.skipGenericOwner == o.fn and
|
||||||
|
tfCapturesEnv in s.typ.flags and s != i.fn:
|
||||||
# call to some other inner proc; we need to track the dependencies for
|
# call to some other inner proc; we need to track the dependencies for
|
||||||
# this:
|
# this:
|
||||||
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
|
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
|
||||||
|
|
@ -314,7 +392,7 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
|
||||||
if o.currentEnv != env:
|
if o.currentEnv != env:
|
||||||
discard addDep(o.currentEnv, env, i.fn)
|
discard addDep(o.currentEnv, env, i.fn)
|
||||||
internalError(n.info, "too complex environment handling required")
|
internalError(n.info, "too complex environment handling required")
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
|
||||||
else:
|
else:
|
||||||
for k in countup(0, sonsLen(n) - 1):
|
for k in countup(0, sonsLen(n) - 1):
|
||||||
gatherVars(o, i, n.sons[k])
|
gatherVars(o, i, n.sons[k])
|
||||||
|
|
@ -366,10 +444,11 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
# captured symbol?
|
# captured symbol?
|
||||||
result = idNodeTableGet(i.localsToAccess, n.sym)
|
result = idNodeTableGet(i.localsToAccess, n.sym)
|
||||||
of nkLambdaKinds:
|
of nkLambdaKinds, nkIteratorDef:
|
||||||
result = transformInnerProc(o, i, n.sons[namePos])
|
if n.typ != nil:
|
||||||
|
result = transformInnerProc(o, i, n.sons[namePos])
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef:
|
nkClosure:
|
||||||
# don't recurse here:
|
# don't recurse here:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
|
|
@ -400,8 +479,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
|
||||||
if inner.closureParam != nil:
|
if inner.closureParam != nil:
|
||||||
let ti = transformInnerProc(o, inner, body)
|
let ti = transformInnerProc(o, inner, body)
|
||||||
if ti != nil: n.sym.ast.sons[bodyPos] = ti
|
if ti != nil: n.sym.ast.sons[bodyPos] = ti
|
||||||
of nkLambdaKinds:
|
of nkLambdaKinds, nkIteratorDef:
|
||||||
searchForInnerProcs(o, n.sons[namePos])
|
if n.typ != nil:
|
||||||
|
searchForInnerProcs(o, n.sons[namePos])
|
||||||
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
|
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
|
||||||
# some nodes open a new scope, so they are candidates for the insertion
|
# some nodes open a new scope, so they are candidates for the insertion
|
||||||
# of closure creation; however for simplicity we merge closures between
|
# of closure creation; however for simplicity we merge closures between
|
||||||
|
|
@ -438,7 +518,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
internalError(it.info, "transformOuter")
|
internalError(it.info, "transformOuter")
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef:
|
nkClosure:
|
||||||
# don't recurse here:
|
# don't recurse here:
|
||||||
# XXX recurse here and setup 'up' pointers
|
# XXX recurse here and setup 'up' pointers
|
||||||
discard
|
discard
|
||||||
|
|
@ -463,19 +543,20 @@ proc addVar*(father, v: PNode) =
|
||||||
addSon(vpart, ast.emptyNode)
|
addSon(vpart, ast.emptyNode)
|
||||||
addSon(father, vpart)
|
addSon(father, vpart)
|
||||||
|
|
||||||
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
|
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
|
||||||
if e.closure == nil:
|
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
incl(result.flags, sfShadowed)
|
||||||
incl(result.flags, sfShadowed)
|
result.typ = newType(tyRef, o.fn)
|
||||||
result.typ = newType(tyRef, o.fn)
|
result.typ.rawAddSon(e.tup)
|
||||||
result.typ.rawAddSon(e.tup)
|
|
||||||
e.closure = result
|
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
||||||
|
if e.createdVar == nil:
|
||||||
|
result = newClosureCreationVar(o, e)
|
||||||
|
e.createdVar = result
|
||||||
else:
|
else:
|
||||||
result = e.closure
|
result = e.createdVar
|
||||||
|
|
||||||
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
|
||||||
var env = getClosureVar(o, scope)
|
|
||||||
|
|
||||||
|
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
|
||||||
result = newNodeI(nkStmtList, env.info)
|
result = newNodeI(nkStmtList, env.info)
|
||||||
var v = newNodeI(nkVarSection, env.info)
|
var v = newNodeI(nkVarSection, env.info)
|
||||||
addVar(v, newSymNode(env))
|
addVar(v, newSymNode(env))
|
||||||
|
|
@ -497,16 +578,90 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||||
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
|
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
|
||||||
newSymNode(getClosureVar(o, e)), env.info))
|
newSymNode(getClosureVar(o, e)), env.info))
|
||||||
|
|
||||||
|
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||||
|
var env = getClosureVar(o, scope)
|
||||||
|
result = rawClosureCreation(o, scope, env)
|
||||||
|
|
||||||
|
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
|
||||||
|
scope: PNode): PSym =
|
||||||
|
result = newClosureCreationVar(o, env)
|
||||||
|
let cc = rawClosureCreation(o, env, result)
|
||||||
|
var insertPoint = scope.sons[0]
|
||||||
|
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
|
||||||
|
else:
|
||||||
|
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
|
||||||
|
for x in cc: insertPoint.add(x)
|
||||||
|
if env.createdVar == nil: env.createdVar = result
|
||||||
|
|
||||||
|
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||||
|
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||||
|
|
||||||
|
proc transformOuterProc(o: POuterContext, n: PNode): PNode
|
||||||
|
|
||||||
|
proc transformYield(c: POuterContext, n: PNode): PNode =
|
||||||
|
inc c.state.typ.n.sons[1].intVal
|
||||||
|
let stateNo = c.state.typ.n.sons[1].intVal
|
||||||
|
|
||||||
|
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||||
|
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||||
|
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||||
|
|
||||||
|
var retStmt = newNodeI(nkReturnStmt, n.info)
|
||||||
|
if n.sons[0].kind != nkEmpty:
|
||||||
|
var a = newNodeI(nkAsgn, n.sons[0].info)
|
||||||
|
var retVal = transformOuterProc(c, n.sons[0])
|
||||||
|
addSon(a, newSymNode(c.resultSym))
|
||||||
|
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
|
||||||
|
retStmt.add(a)
|
||||||
|
else:
|
||||||
|
retStmt.add(emptyNode)
|
||||||
|
|
||||||
|
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||||
|
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||||
|
|
||||||
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
result.add(stateAsgnStmt)
|
||||||
|
result.add(retStmt)
|
||||||
|
result.add(stateLabelStmt)
|
||||||
|
|
||||||
|
proc transformReturn(c: POuterContext, n: PNode): PNode =
|
||||||
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||||
|
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||||
|
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||||
|
result.add(stateAsgnStmt)
|
||||||
|
result.add(n)
|
||||||
|
|
||||||
|
proc outerProcSons(o: POuterContext, n: PNode) =
|
||||||
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
let x = transformOuterProc(o, n.sons[i])
|
||||||
|
if x != nil: n.sons[i] = x
|
||||||
|
|
||||||
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
if n == nil: return nil
|
if n == nil: return nil
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
||||||
of nkSym:
|
of nkSym:
|
||||||
var local = n.sym
|
var local = n.sym
|
||||||
|
|
||||||
|
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
|
||||||
|
if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local)
|
||||||
|
return indirectAccess(newSymNode(o.closureParam), local, n.info)
|
||||||
|
|
||||||
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
||||||
if closure != nil:
|
if closure != nil:
|
||||||
# we need to replace the lambda with '(lambda, env)':
|
# we need to replace the lambda with '(lambda, env)':
|
||||||
let a = closure.closure
|
if local.kind == skIterator and local.typ.callConv == ccClosure:
|
||||||
|
# consider: [i1, i2, i1] Since we merged the iterator's closure
|
||||||
|
# with the captured owning variables, we need to generate the
|
||||||
|
# closure generation code again:
|
||||||
|
#if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
|
||||||
|
# XXX why doesn't this work?
|
||||||
|
let createdVar = generateIterClosureCreation(o, closure,
|
||||||
|
closure.attachedNode)
|
||||||
|
return makeClosure(local, createdVar, n.info)
|
||||||
|
|
||||||
|
let a = closure.createdVar
|
||||||
if a != nil:
|
if a != nil:
|
||||||
return makeClosure(local, a, n.info)
|
return makeClosure(local, a, n.info)
|
||||||
else:
|
else:
|
||||||
|
|
@ -516,7 +671,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
if scope.sons[0].kind == nkEmpty:
|
if scope.sons[0].kind == nkEmpty:
|
||||||
# change the empty node to contain the closure construction:
|
# change the empty node to contain the closure construction:
|
||||||
scope.sons[0] = generateClosureCreation(o, closure)
|
scope.sons[0] = generateClosureCreation(o, closure)
|
||||||
let x = closure.closure
|
let x = closure.createdVar
|
||||||
assert x != nil
|
assert x != nil
|
||||||
return makeClosure(local, x, n.info)
|
return makeClosure(local, x, n.info)
|
||||||
|
|
||||||
|
|
@ -535,20 +690,47 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
assert result != nil, "cannot find: " & local.name.s
|
assert result != nil, "cannot find: " & local.name.s
|
||||||
# else it is captured by copy and this means that 'outer' should continue
|
# else it is captured by copy and this means that 'outer' should continue
|
||||||
# to access the local as a local.
|
# to access the local as a local.
|
||||||
of nkLambdaKinds:
|
of nkLambdaKinds, nkIteratorDef:
|
||||||
result = transformOuterProc(o, n.sons[namePos])
|
if n.typ != nil:
|
||||||
|
result = transformOuterProc(o, n.sons[namePos])
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef:
|
nkClosure:
|
||||||
# don't recurse here:
|
# don't recurse here:
|
||||||
discard
|
discard
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
let x = transformOuterProc(o, n.sons[1])
|
let x = transformOuterProc(o, n.sons[1])
|
||||||
if x != nil: n.sons[1] = x
|
if x != nil: n.sons[1] = x
|
||||||
result = transformOuterConv(n)
|
result = transformOuterConv(n)
|
||||||
|
of nkYieldStmt:
|
||||||
|
if o.isIter: result = transformYield(o, n)
|
||||||
|
else: outerProcSons(o, n)
|
||||||
|
of nkReturnStmt:
|
||||||
|
if o.isIter: result = transformReturn(o, n)
|
||||||
|
else: outerProcSons(o, n)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
outerProcSons(o, n)
|
||||||
let x = transformOuterProc(o, n.sons[i])
|
|
||||||
if x != nil: n.sons[i] = x
|
proc liftIterator(c: POuterContext, body: PNode): PNode =
|
||||||
|
let iter = c.fn
|
||||||
|
result = newNodeI(nkStmtList, iter.info)
|
||||||
|
var gs = newNodeI(nkGotoState, iter.info)
|
||||||
|
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
|
||||||
|
result.add(gs)
|
||||||
|
var state0 = newNodeI(nkState, iter.info)
|
||||||
|
state0.add(newIntNode(nkIntLit, 0))
|
||||||
|
result.add(state0)
|
||||||
|
|
||||||
|
let newBody = transformOuterProc(c, body)
|
||||||
|
if newBody != nil:
|
||||||
|
result.add(newBody)
|
||||||
|
else:
|
||||||
|
result.add(body)
|
||||||
|
|
||||||
|
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
|
||||||
|
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
|
||||||
|
c.state,iter.info))
|
||||||
|
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||||
|
result.add(stateAsgnStmt)
|
||||||
|
|
||||||
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||||
|
|
@ -572,8 +754,11 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||||
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
|
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
|
||||||
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
|
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
|
||||||
searchForInnerProcs(o, body)
|
searchForInnerProcs(o, body)
|
||||||
discard transformOuterProc(o, body)
|
if o.isIter:
|
||||||
result = ex
|
result = liftIterator(o, ex)
|
||||||
|
else:
|
||||||
|
discard transformOuterProc(o, body)
|
||||||
|
result = ex
|
||||||
|
|
||||||
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
||||||
|
|
@ -588,140 +773,15 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||||
|
|
||||||
# ------------------- iterator transformation --------------------------------
|
# ------------------- iterator transformation --------------------------------
|
||||||
|
|
||||||
discard """
|
|
||||||
iterator chain[S, T](a, b: *S->T, args: *S): T =
|
|
||||||
for x in a(args): yield x
|
|
||||||
for x in b(args): yield x
|
|
||||||
|
|
||||||
let c = chain(f, g)
|
|
||||||
for x in c: echo x
|
|
||||||
|
|
||||||
# translated to:
|
|
||||||
let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
|
|
||||||
"""
|
|
||||||
|
|
||||||
type
|
|
||||||
TIterContext {.final, pure.} = object
|
|
||||||
iter, closureParam, state, resultSym: PSym
|
|
||||||
capturedVars: TIntSet
|
|
||||||
tup: PType
|
|
||||||
|
|
||||||
proc newIterResult(iter: PSym): PSym =
|
|
||||||
result = iter.ast.sons[resultPos].sym
|
|
||||||
when false:
|
|
||||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
|
||||||
result.typ = iter.typ.sons[0]
|
|
||||||
incl(result.flags, sfUsed)
|
|
||||||
|
|
||||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
|
||||||
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
|
||||||
|
|
||||||
proc transfIterBody(c: var TIterContext, n: PNode): PNode =
|
|
||||||
# gather used vars for closure generation
|
|
||||||
if n == nil: return nil
|
|
||||||
case n.kind
|
|
||||||
of nkSym:
|
|
||||||
var s = n.sym
|
|
||||||
if interestingIterVar(s) and c.iter.id == s.owner.id:
|
|
||||||
if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
|
|
||||||
result = indirectAccess(newSymNode(c.closureParam), s, n.info)
|
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
|
||||||
of nkYieldStmt:
|
|
||||||
inc c.state.typ.n.sons[1].intVal
|
|
||||||
let stateNo = c.state.typ.n.sons[1].intVal
|
|
||||||
|
|
||||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
|
||||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
|
||||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
|
||||||
|
|
||||||
var retStmt = newNodeI(nkReturnStmt, n.info)
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
|
||||||
var a = newNodeI(nkAsgn, n.sons[0].info)
|
|
||||||
var retVal = transfIterBody(c, n.sons[0])
|
|
||||||
addSon(a, newSymNode(c.resultSym))
|
|
||||||
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
|
|
||||||
retStmt.add(a)
|
|
||||||
else:
|
|
||||||
retStmt.add(emptyNode)
|
|
||||||
|
|
||||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
|
||||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
|
||||||
|
|
||||||
result = newNodeI(nkStmtList, n.info)
|
|
||||||
result.add(stateAsgnStmt)
|
|
||||||
result.add(retStmt)
|
|
||||||
result.add(stateLabelStmt)
|
|
||||||
of nkReturnStmt:
|
|
||||||
result = newNodeI(nkStmtList, n.info)
|
|
||||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
|
||||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
|
||||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
|
||||||
result.add(stateAsgnStmt)
|
|
||||||
result.add(n)
|
|
||||||
else:
|
|
||||||
for i in countup(0, sonsLen(n)-1):
|
|
||||||
let x = transfIterBody(c, n.sons[i])
|
|
||||||
if x != nil: n.sons[i] = x
|
|
||||||
|
|
||||||
proc getStateType(iter: PSym): PType =
|
|
||||||
var n = newNodeI(nkRange, iter.info)
|
|
||||||
addSon(n, newIntNode(nkIntLit, -1))
|
|
||||||
addSon(n, newIntNode(nkIntLit, 0))
|
|
||||||
result = newType(tyRange, iter)
|
|
||||||
result.n = n
|
|
||||||
rawAddSon(result, getSysType(tyInt))
|
|
||||||
|
|
||||||
proc liftIterator*(iter: PSym, body: PNode): PNode =
|
|
||||||
var c: TIterContext
|
|
||||||
c.iter = iter
|
|
||||||
c.capturedVars = initIntSet()
|
|
||||||
|
|
||||||
c.tup = newType(tyTuple, iter)
|
|
||||||
c.tup.n = newNodeI(nkRecList, iter.info)
|
|
||||||
|
|
||||||
var cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
|
||||||
incl(cp.flags, sfFromGeneric)
|
|
||||||
cp.typ = newType(tyRef, iter)
|
|
||||||
rawAddSon(cp.typ, c.tup)
|
|
||||||
c.closureParam = cp
|
|
||||||
addHiddenParam(iter, cp)
|
|
||||||
|
|
||||||
c.state = newSym(skField, getIdent(":state"), iter, iter.info)
|
|
||||||
c.state.typ = getStateType(iter)
|
|
||||||
addField(c.tup, c.state)
|
|
||||||
|
|
||||||
if iter.typ.sons[0] != nil:
|
|
||||||
c.resultSym = newIterResult(iter)
|
|
||||||
iter.ast.add(newSymNode(c.resultSym))
|
|
||||||
|
|
||||||
result = newNodeI(nkStmtList, iter.info)
|
|
||||||
var gs = newNodeI(nkGotoState, iter.info)
|
|
||||||
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
|
|
||||||
result.add(gs)
|
|
||||||
var state0 = newNodeI(nkState, iter.info)
|
|
||||||
state0.add(newIntNode(nkIntLit, 0))
|
|
||||||
result.add(state0)
|
|
||||||
|
|
||||||
let newBody = transfIterBody(c, body)
|
|
||||||
if newBody != nil:
|
|
||||||
result.add(newBody)
|
|
||||||
else:
|
|
||||||
result.add(body)
|
|
||||||
|
|
||||||
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
|
|
||||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
|
|
||||||
c.state,iter.info))
|
|
||||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
|
||||||
result.add(stateAsgnStmt)
|
|
||||||
|
|
||||||
proc liftIterSym*(n: PNode): PNode =
|
proc liftIterSym*(n: PNode): PNode =
|
||||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
|
||||||
let iter = n.sym
|
let iter = n.sym
|
||||||
assert iter.kind == skIterator
|
assert iter.kind == skIterator
|
||||||
|
|
||||||
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
|
|
||||||
var env = copySym(getHiddenParam(iter))
|
var env = copySym(getHiddenParam(iter))
|
||||||
env.kind = skLet
|
env.kind = skLet
|
||||||
|
|
||||||
var v = newNodeI(nkVarSection, n.info)
|
var v = newNodeI(nkVarSection, n.info)
|
||||||
addVar(v, newSymNode(env))
|
addVar(v, newSymNode(env))
|
||||||
result.add(v)
|
result.add(v)
|
||||||
|
|
@ -766,7 +826,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||||
# static binding?
|
# static binding?
|
||||||
var env: PSym
|
var env: PSym
|
||||||
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
|
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
|
||||||
# createClose()
|
# createClosure()
|
||||||
let iter = call[0].sym
|
let iter = call[0].sym
|
||||||
assert iter.kind == skIterator
|
assert iter.kind == skIterator
|
||||||
env = copySym(getHiddenParam(iter))
|
env = copySym(getHiddenParam(iter))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -18,10 +18,10 @@
|
||||||
# In fact the grammar is generated from this file:
|
# In fact the grammar is generated from this file:
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
import pegs
|
import pegs
|
||||||
var outp = open("compiler/grammar.txt", fmWrite)
|
var outp = open("doc/grammar.txt", fmWrite)
|
||||||
for line in lines("compiler/parser.nim"):
|
for line in lines("compiler/parser.nim"):
|
||||||
if line =~ peg" \s* '#| ' {.*}":
|
if line =~ peg" \s* '#| ' {.*}":
|
||||||
outp.writeln matches[0]
|
outp.write matches[0], "\L"
|
||||||
outp.close
|
outp.close
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
@ -31,9 +31,10 @@ type
|
||||||
TParser*{.final.} = object # a TParser object represents a module that
|
TParser*{.final.} = object # a TParser object represents a module that
|
||||||
# is being parsed
|
# is being parsed
|
||||||
currInd: int # current indentation
|
currInd: int # current indentation
|
||||||
firstTok: bool
|
firstTok, strongSpaces: bool
|
||||||
lex*: TLexer # the lexer that is used for parsing
|
lex*: TLexer # the lexer that is used for parsing
|
||||||
tok*: TToken # the current token
|
tok*: TToken # the current token
|
||||||
|
inPragma: int
|
||||||
|
|
||||||
proc parseAll*(p: var TParser): PNode
|
proc parseAll*(p: var TParser): PNode
|
||||||
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
|
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
|
||||||
|
|
@ -518,14 +519,14 @@ proc parsePar(p: var TParser): PNode =
|
||||||
eat(p, tkParRi)
|
eat(p, tkParRi)
|
||||||
|
|
||||||
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
|
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
|
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||||
|
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||||
|
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
|
#| | CHAR_LIT
|
||||||
|
#| | NIL
|
||||||
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||||
#| identOrLiteral = generalizedLit | symbol
|
#| identOrLiteral = generalizedLit | symbol | literal
|
||||||
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
|
||||||
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
|
||||||
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
|
||||||
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
|
||||||
#| | CHAR_LIT
|
|
||||||
#| | NIL
|
|
||||||
#| | par | arrayConstr | setOrTableConstr
|
#| | par | arrayConstr | setOrTableConstr
|
||||||
#| | castExpr
|
#| | castExpr
|
||||||
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||||
|
|
@ -634,12 +635,15 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
exprColonEqExprListAux(p, endTok, result)
|
exprColonEqExprListAux(p, endTok, result)
|
||||||
|
|
||||||
|
proc parseMacroColon(p: var TParser, x: PNode): PNode
|
||||||
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
#| | doBlocks
|
#| | doBlocks
|
||||||
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
||||||
#| | '[' optInd indexExprList optPar ']'
|
#| | '[' optInd indexExprList optPar ']'
|
||||||
#| | '{' optInd indexExprList optPar '}'
|
#| | '{' optInd indexExprList optPar '}'
|
||||||
|
#| | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
|
||||||
|
#| (doBlock | macroColon)?
|
||||||
result = r
|
result = r
|
||||||
while p.tok.indent < 0:
|
while p.tok.indent < 0:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -661,7 +665,26 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||||
of tkCurlyLe:
|
of tkCurlyLe:
|
||||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||||
else: break
|
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
|
||||||
|
if p.inPragma == 0:
|
||||||
|
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
|
||||||
|
# solution, but pragmas.nim can't handle that
|
||||||
|
let a = result
|
||||||
|
result = newNodeP(nkCommand, p)
|
||||||
|
addSon(result, a)
|
||||||
|
while p.tok.tokType != tkEof:
|
||||||
|
let a = parseExpr(p)
|
||||||
|
addSon(result, a)
|
||||||
|
if p.tok.tokType != tkComma: break
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, a)
|
||||||
|
if p.tok.tokType == tkDo:
|
||||||
|
parseDoBlocks(p, result)
|
||||||
|
else:
|
||||||
|
result = parseMacroColon(p, result)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||||
|
|
||||||
|
|
@ -713,6 +736,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||||
proc parsePragma(p: var TParser): PNode =
|
proc parsePragma(p: var TParser): PNode =
|
||||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||||
result = newNodeP(nkPragma, p)
|
result = newNodeP(nkPragma, p)
|
||||||
|
inc p.inPragma
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
||||||
|
|
@ -724,6 +748,7 @@ proc parsePragma(p: var TParser): PNode =
|
||||||
optPar(p)
|
optPar(p)
|
||||||
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
||||||
else: parMessage(p, errTokenExpected, ".}")
|
else: parMessage(p, errTokenExpected, ".}")
|
||||||
|
dec p.inPragma
|
||||||
|
|
||||||
proc identVis(p: var TParser): PNode =
|
proc identVis(p: var TParser): PNode =
|
||||||
#| identVis = symbol opr? # postfix position
|
#| identVis = symbol opr? # postfix position
|
||||||
|
|
@ -965,7 +990,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||||
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||||
of tkIterator:
|
of tkIterator:
|
||||||
when true:
|
when false:
|
||||||
if mode in {pmTypeDesc, pmTypeDef}:
|
if mode in {pmTypeDesc, pmTypeDef}:
|
||||||
result = parseProcExpr(p, false)
|
result = parseProcExpr(p, false)
|
||||||
result.kind = nkIteratorTy
|
result.kind = nkIteratorTy
|
||||||
|
|
@ -976,7 +1001,8 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
else:
|
else:
|
||||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||||
result.kind = nkIteratorTy
|
if result.kind == nkLambda: result.kind = nkIteratorDef
|
||||||
|
else: result.kind = nkIteratorTy
|
||||||
of tkEnum:
|
of tkEnum:
|
||||||
if mode == pmTypeDef:
|
if mode == pmTypeDef:
|
||||||
result = parseEnum(p)
|
result = parseEnum(p)
|
||||||
|
|
@ -1022,6 +1048,7 @@ proc parseTypeDesc(p: var TParser): PNode =
|
||||||
|
|
||||||
proc parseTypeDefAux(p: var TParser): PNode =
|
proc parseTypeDefAux(p: var TParser): PNode =
|
||||||
#| typeDefAux = simpleExpr
|
#| typeDefAux = simpleExpr
|
||||||
|
#| | 'generic' typeClass
|
||||||
result = simpleExpr(p, pmTypeDef)
|
result = simpleExpr(p, pmTypeDef)
|
||||||
|
|
||||||
proc makeCall(n: PNode): PNode =
|
proc makeCall(n: PNode): PNode =
|
||||||
|
|
@ -1031,15 +1058,50 @@ proc makeCall(n: PNode): PNode =
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
result.add n
|
result.add n
|
||||||
|
|
||||||
|
proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||||
|
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||||
|
#| | IND{=} 'elif' expr ':' stmt
|
||||||
|
#| | IND{=} 'except' exprList ':' stmt
|
||||||
|
#| | IND{=} 'else' ':' stmt )*
|
||||||
|
result = x
|
||||||
|
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||||
|
result = makeCall(result)
|
||||||
|
getTok(p)
|
||||||
|
skipComment(p, result)
|
||||||
|
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||||
|
let body = parseStmt(p)
|
||||||
|
addSon(result, newProcNode(nkDo, body.info, body))
|
||||||
|
while sameInd(p):
|
||||||
|
var b: PNode
|
||||||
|
case p.tok.tokType
|
||||||
|
of tkOf:
|
||||||
|
b = newNodeP(nkOfBranch, p)
|
||||||
|
exprList(p, tkColon, b)
|
||||||
|
of tkElif:
|
||||||
|
b = newNodeP(nkElifBranch, p)
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, b)
|
||||||
|
addSon(b, parseExpr(p))
|
||||||
|
eat(p, tkColon)
|
||||||
|
of tkExcept:
|
||||||
|
b = newNodeP(nkExceptBranch, p)
|
||||||
|
exprList(p, tkColon, b)
|
||||||
|
skipComment(p, b)
|
||||||
|
of tkElse:
|
||||||
|
b = newNodeP(nkElse, p)
|
||||||
|
getTok(p)
|
||||||
|
eat(p, tkColon)
|
||||||
|
else: break
|
||||||
|
addSon(b, parseStmt(p))
|
||||||
|
addSon(result, b)
|
||||||
|
if b.kind == nkElse: break
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
#| exprStmt = simpleExpr
|
#| exprStmt = simpleExpr
|
||||||
#| (( '=' optInd expr )
|
#| (( '=' optInd expr )
|
||||||
#| / ( expr ^+ comma
|
#| / ( expr ^+ comma
|
||||||
#| doBlocks
|
#| doBlocks
|
||||||
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
#| / macroColon
|
||||||
#| | IND{=} 'elif' expr ':' stmt
|
|
||||||
#| | IND{=} 'except' exprList ':' stmt
|
|
||||||
#| | IND{=} 'else' ':' stmt )*
|
|
||||||
#| ))?
|
#| ))?
|
||||||
var a = simpleExpr(p)
|
var a = simpleExpr(p)
|
||||||
if p.tok.tokType == tkEquals:
|
if p.tok.tokType == tkEquals:
|
||||||
|
|
@ -1064,37 +1126,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||||
result = makeCall(result)
|
result = makeCall(result)
|
||||||
parseDoBlocks(p, result)
|
parseDoBlocks(p, result)
|
||||||
return result
|
return result
|
||||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
result = parseMacroColon(p, result)
|
||||||
result = makeCall(result)
|
|
||||||
getTok(p)
|
|
||||||
skipComment(p, result)
|
|
||||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
|
||||||
let body = parseStmt(p)
|
|
||||||
addSon(result, newProcNode(nkDo, body.info, body))
|
|
||||||
while sameInd(p):
|
|
||||||
var b: PNode
|
|
||||||
case p.tok.tokType
|
|
||||||
of tkOf:
|
|
||||||
b = newNodeP(nkOfBranch, p)
|
|
||||||
exprList(p, tkColon, b)
|
|
||||||
of tkElif:
|
|
||||||
b = newNodeP(nkElifBranch, p)
|
|
||||||
getTok(p)
|
|
||||||
optInd(p, b)
|
|
||||||
addSon(b, parseExpr(p))
|
|
||||||
eat(p, tkColon)
|
|
||||||
of tkExcept:
|
|
||||||
b = newNodeP(nkExceptBranch, p)
|
|
||||||
exprList(p, tkColon, b)
|
|
||||||
skipComment(p, b)
|
|
||||||
of tkElse:
|
|
||||||
b = newNodeP(nkElse, p)
|
|
||||||
getTok(p)
|
|
||||||
eat(p, tkColon)
|
|
||||||
else: break
|
|
||||||
addSon(b, parseStmt(p))
|
|
||||||
addSon(result, b)
|
|
||||||
if b.kind == nkElse: break
|
|
||||||
|
|
||||||
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = parseExpr(p)
|
result = parseExpr(p)
|
||||||
|
|
@ -1177,8 +1209,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||||
if p.tok.tokType == tkComment:
|
if p.tok.tokType == tkComment:
|
||||||
skipComment(p, result)
|
skipComment(p, result)
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
|
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
|
||||||
p.tok.tokType == tkEof:
|
|
||||||
# NL terminates:
|
# NL terminates:
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1641,6 +1672,9 @@ proc parseTypeClassParam(p: var TParser): PNode =
|
||||||
result = p.parseSymbol
|
result = p.parseSymbol
|
||||||
|
|
||||||
proc parseTypeClass(p: var TParser): PNode =
|
proc parseTypeClass(p: var TParser): PNode =
|
||||||
|
#| typeClassParam = ('var')? symbol
|
||||||
|
#| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||||
|
#| &IND{>} stmt
|
||||||
result = newNodeP(nkTypeClassTy, p)
|
result = newNodeP(nkTypeClassTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
var args = newNode(nkArgList)
|
var args = newNode(nkArgList)
|
||||||
|
|
|
||||||
|
|
@ -426,6 +426,8 @@ proc lsub(n: PNode): int =
|
||||||
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
|
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
|
||||||
of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) +
|
of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) +
|
||||||
len("Distinct")
|
len("Distinct")
|
||||||
|
of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
|
||||||
|
len("static[]")
|
||||||
of nkTypeDef: result = lsons(n) + 3
|
of nkTypeDef: result = lsons(n) + 3
|
||||||
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
|
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
|
||||||
of nkProcTy: result = lsons(n) + len("proc_")
|
of nkProcTy: result = lsons(n) + len("proc_")
|
||||||
|
|
@ -701,6 +703,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||||
gcoms(g)
|
gcoms(g)
|
||||||
dedent(g)
|
dedent(g)
|
||||||
|
|
||||||
|
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
|
||||||
|
var c: TContext
|
||||||
|
initContext(c)
|
||||||
|
putWithSpace(g, tkGeneric, "generic")
|
||||||
|
gsons(g, n[0], c) # arglist
|
||||||
|
gsub(g, n[1]) # pragmas
|
||||||
|
gsub(g, n[2]) # of
|
||||||
|
gcoms(g)
|
||||||
|
indentNL(g)
|
||||||
|
gcoms(g)
|
||||||
|
gstmts(g, n[3], c)
|
||||||
|
dedent(g)
|
||||||
|
|
||||||
proc gblock(g: var TSrcGen, n: PNode) =
|
proc gblock(g: var TSrcGen, n: PNode) =
|
||||||
var c: TContext
|
var c: TContext
|
||||||
initContext(c)
|
initContext(c)
|
||||||
|
|
@ -1054,6 +1069,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
else:
|
else:
|
||||||
put(g, tkShared, "shared")
|
put(g, tkShared, "shared")
|
||||||
|
of nkStaticTy:
|
||||||
|
put(g, tkStatic, "static")
|
||||||
|
put(g, tkBracketLe, "[")
|
||||||
|
if n.len > 0:
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
put(g, tkBracketRi, "]")
|
||||||
of nkEnumTy:
|
of nkEnumTy:
|
||||||
if sonsLen(n) > 0:
|
if sonsLen(n) > 0:
|
||||||
putWithSpace(g, tkEnum, "enum")
|
putWithSpace(g, tkEnum, "enum")
|
||||||
|
|
@ -1251,6 +1272,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
put(g, tkParLe, "(META|")
|
put(g, tkParLe, "(META|")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
put(g, tkParRi, ")")
|
put(g, tkParRi, ")")
|
||||||
|
of nkGotoState, nkState:
|
||||||
|
var c: TContext
|
||||||
|
initContext c
|
||||||
|
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
|
||||||
|
gsons(g, n, c)
|
||||||
|
of nkTypeClassTy:
|
||||||
|
gTypeClassTy(g, n)
|
||||||
else:
|
else:
|
||||||
#nkNone, nkExplicitTypeListCall:
|
#nkNone, nkExplicitTypeListCall:
|
||||||
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,10 @@ proc generateDestructor(c: PContext, t: PType): PNode =
|
||||||
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
|
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
|
||||||
if stmt != nil: addLine(stmt)
|
if stmt != nil: addLine(stmt)
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
# XXX just skip it for now so that the compiler doesn't crash, but
|
||||||
|
# please zahary fix it! arbitrary nesting of nkRecList/nkRecCase is
|
||||||
|
# possible. Any thread example seems to trigger this.
|
||||||
|
discard
|
||||||
# base classes' destructors will be automatically called by
|
# base classes' destructors will be automatically called by
|
||||||
# semProcAux for both auto-generated and user-defined destructors
|
# semProcAux for both auto-generated and user-defined destructors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
localError(n.info, errXExpectsTypeOrValue, opToStr[m])
|
localError(n.info, errXExpectsTypeOrValue, opToStr[m])
|
||||||
else:
|
else:
|
||||||
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||||
var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc})
|
var typ = skipTypes(n.sons[1].typ, abstractVarRange +
|
||||||
|
{tyTypeDesc, tyFieldAccessor})
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tySequence, tyString, tyOpenArray, tyVarargs:
|
of tySequence, tyString, tyOpenArray, tyVarargs:
|
||||||
n.typ = getSysType(tyInt)
|
n.typ = getSysType(tyInt)
|
||||||
|
|
@ -247,7 +248,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
n.typ = typ.sons[0] # indextype
|
n.typ = typ.sons[0] # indextype
|
||||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
|
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
|
||||||
# do not skip the range!
|
# do not skip the range!
|
||||||
n.typ = n.sons[1].typ.skipTypes(abstractVar)
|
n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
# prepare this for resolving in semtypinst:
|
# prepare this for resolving in semtypinst:
|
||||||
# we must use copyTree here in order to avoid creating a cycle
|
# we must use copyTree here in order to avoid creating a cycle
|
||||||
|
|
@ -306,7 +307,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
|
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
|
||||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||||
|
|
||||||
let t1 = n[1].typ.skipTypes({tyTypeDesc})
|
let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
|
||||||
|
|
||||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
case n[2].strVal.normalize
|
case n[2].strVal.normalize
|
||||||
|
|
@ -321,24 +322,13 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
t.callConv == ccClosure and
|
t.callConv == ccClosure and
|
||||||
tfIterator in t.flags))
|
tfIterator in t.flags))
|
||||||
else:
|
else:
|
||||||
var match: bool
|
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
||||||
let t2 = n[2].typ
|
let lifted = liftParamType(c, skType, newNodeI(nkArgList, n.info),
|
||||||
case t2.kind
|
t2, ":anon", n.info)
|
||||||
of tyTypeClasses:
|
if lifted != nil: t2 = lifted
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, t2)
|
initCandidate(c, m, t2)
|
||||||
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
let match = typeRel(m, t2, t1) != isNone
|
||||||
of tyOrdinal:
|
|
||||||
var m: TCandidate
|
|
||||||
initCandidate(c, m, t2)
|
|
||||||
match = isOrdinalType(t1)
|
|
||||||
of tySequence, tyArray, tySet:
|
|
||||||
var m: TCandidate
|
|
||||||
initCandidate(c, m, t2)
|
|
||||||
match = typeRel(m, t2, t1) != isNone
|
|
||||||
else:
|
|
||||||
match = sameType(t1, t2)
|
|
||||||
|
|
||||||
result = newIntNode(nkIntLit, ord(match))
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
|
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
|
|
@ -948,6 +938,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
|
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
|
||||||
return
|
return
|
||||||
|
of tyObject, tyTuple:
|
||||||
|
if ty.n.kind == nkRecList:
|
||||||
|
for field in ty.n.sons:
|
||||||
|
if field.sym.name == i:
|
||||||
|
n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
|
||||||
|
n.typ.n = copyTree(n)
|
||||||
|
return n
|
||||||
else:
|
else:
|
||||||
# echo "TYPE FIELD ACCESS"
|
# echo "TYPE FIELD ACCESS"
|
||||||
# debug ty
|
# debug ty
|
||||||
|
|
|
||||||
|
|
@ -252,8 +252,7 @@ proc evalIs(n, a: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
||||||
let t2 = n[2].typ
|
let t2 = n[2].typ
|
||||||
var match = if t2.kind == tyTypeClass: true
|
var match = sameType(t1, t2)
|
||||||
else: sameType(t1, t2)
|
|
||||||
result = newIntNode(nkIntLit, ord(match))
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -868,6 +868,8 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
||||||
return semStmt(c, x)
|
return semStmt(c, x)
|
||||||
|
|
||||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
# XXX semProcAux should be good enough for this now, we will eventually
|
||||||
|
# remove semLambda
|
||||||
result = semProcAnnotation(c, n)
|
result = semProcAnnotation(c, n)
|
||||||
if result != nil: return result
|
if result != nil: return result
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -922,7 +924,7 @@ proc activate(c: PContext, n: PNode) =
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
for i in 1 .. <n.len: activate(c, n[i])
|
for i in 1 .. <n.len: activate(c, n[i])
|
||||||
else:
|
else:
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||||
if s.typ.sons[0] != nil and
|
if s.typ.sons[0] != nil and
|
||||||
|
|
@ -949,9 +951,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
var s: PSym
|
var s: PSym
|
||||||
var typeIsDetermined = false
|
var typeIsDetermined = false
|
||||||
|
var isAnon = false
|
||||||
if n[namePos].kind != nkSym:
|
if n[namePos].kind != nkSym:
|
||||||
assert phase == stepRegisterSymbol
|
assert phase == stepRegisterSymbol
|
||||||
s = semIdentDef(c, n.sons[0], kind)
|
|
||||||
|
if n[namePos].kind == nkEmpty:
|
||||||
|
s = newSym(kind, idAnon, getCurrOwner(), n.info)
|
||||||
|
isAnon = true
|
||||||
|
else:
|
||||||
|
s = semIdentDef(c, n.sons[0], kind)
|
||||||
n.sons[namePos] = newSymNode(s)
|
n.sons[namePos] = newSymNode(s)
|
||||||
s.ast = n
|
s.ast = n
|
||||||
s.scope = c.currentScope
|
s.scope = c.currentScope
|
||||||
|
|
@ -992,11 +1000,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
rawAddSon(s.typ, nil)
|
rawAddSon(s.typ, nil)
|
||||||
if n.sons[patternPos].kind != nkEmpty:
|
if n.sons[patternPos].kind != nkEmpty:
|
||||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||||
if s.kind == skIterator: s.typ.flags.incl(tfIterator)
|
if s.kind == skIterator:
|
||||||
|
s.typ.flags.incl(tfIterator)
|
||||||
|
|
||||||
var proto = searchForProc(c, s.scope, s)
|
var proto = searchForProc(c, s.scope, s)
|
||||||
if proto == nil:
|
if proto == nil:
|
||||||
s.typ.callConv = lastOptionEntry(c).defaultCC
|
if s.kind == skIterator and isAnon: s.typ.callConv = ccClosure
|
||||||
|
else: s.typ.callConv = lastOptionEntry(c).defaultCC
|
||||||
# add it here, so that recursive procs are possible:
|
# add it here, so that recursive procs are possible:
|
||||||
if sfGenSym in s.flags: discard
|
if sfGenSym in s.flags: discard
|
||||||
elif kind in OverloadableSyms:
|
elif kind in OverloadableSyms:
|
||||||
|
|
@ -1074,6 +1084,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
popOwner()
|
popOwner()
|
||||||
if n.sons[patternPos].kind != nkEmpty:
|
if n.sons[patternPos].kind != nkEmpty:
|
||||||
c.patterns.add(s)
|
c.patterns.add(s)
|
||||||
|
if isAnon: result.typ = s.typ
|
||||||
|
|
||||||
proc determineType(c: PContext, s: PSym) =
|
proc determineType(c: PContext, s: PSym) =
|
||||||
if s.typ != nil: return
|
if s.typ != nil: return
|
||||||
|
|
@ -1236,7 +1247,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
||||||
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = enforceVoidContext
|
n.typ = enforceVoidContext
|
||||||
if i != last or voidContext:
|
if i != last or voidContext or c.inTypeClass > 0:
|
||||||
discardCheck(c, n.sons[i])
|
discardCheck(c, n.sons[i])
|
||||||
else:
|
else:
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
|
|
|
||||||
|
|
@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
result = addImplicitGeneric(result)
|
result = addImplicitGeneric(result)
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
|
if paramType.lastSon.kind == tyUserTypeClass:
|
||||||
|
var cp = copyType(paramType, getCurrOwner(), false)
|
||||||
|
cp.kind = tyUserTypeClassInst
|
||||||
|
return addImplicitGeneric(cp)
|
||||||
|
|
||||||
for i in 1 .. (paramType.sons.len - 2):
|
for i in 1 .. (paramType.sons.len - 2):
|
||||||
var lifted = liftingWalk(paramType.sons[i])
|
var lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil:
|
if lifted != nil:
|
||||||
|
|
@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = liftingWalk(expanded)
|
result = liftingWalk(expanded)
|
||||||
|
|
||||||
of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
|
|
@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
|
|
||||||
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
result = newOrPrevType(tyTypeClass, prev, c)
|
result = newOrPrevType(tyUserTypeClass, prev, c)
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,8 @@ proc hasGenericArguments*(n: PNode): bool =
|
||||||
(n.sym.kind == skType and
|
(n.sym.kind == skType and
|
||||||
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
|
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
|
||||||
else:
|
else:
|
||||||
for s in n.sons:
|
for i in 0.. <n.safeLen:
|
||||||
if hasGenericArguments(s): return true
|
if hasGenericArguments(n.sons[i]): return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
|
|
@ -361,6 +361,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
elif t.sonsLen > 0:
|
elif t.sonsLen > 0:
|
||||||
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
||||||
|
|
||||||
|
of tyUserTypeClass:
|
||||||
|
result = t
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
result = instCopyType(cl, t)
|
result = instCopyType(cl, t)
|
||||||
for i in 1 .. <result.sonsLen:
|
for i in 1 .. <result.sonsLen:
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
||||||
var formalTypeParam = typeParams.sons[i-1].typ
|
var formalTypeParam = typeParams.sons[i-1].typ
|
||||||
var bound = binding[i].typ
|
var bound = binding[i].typ
|
||||||
if formalTypeParam.kind != tyTypeDesc:
|
if bound != nil and formalTypeParam.kind != tyTypeDesc:
|
||||||
bound = bound.skipTypes({tyTypeDesc})
|
bound = bound.skipTypes({tyTypeDesc})
|
||||||
put(c.bindings, formalTypeParam, bound)
|
put(c.bindings, formalTypeParam, bound)
|
||||||
|
|
||||||
|
|
@ -140,7 +140,7 @@ proc sumGeneric(t: PType): int =
|
||||||
result = ord(t.kind == tyGenericInvokation)
|
result = ord(t.kind == tyGenericInvokation)
|
||||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc, tyTypeClass: break
|
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
proc complexDisambiguation(a, b: PType): int =
|
proc complexDisambiguation(a, b: PType): int =
|
||||||
|
|
@ -399,6 +399,70 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
|
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
ff, a: PType): TTypeRelation =
|
||||||
|
#if f.n == nil:
|
||||||
|
# let r = typeRel(m, f, a)
|
||||||
|
# return if r == isGeneric: arg else: nil
|
||||||
|
|
||||||
|
var body = ff.skipTypes({tyUserTypeClassInst})
|
||||||
|
|
||||||
|
# var prev = PType(idTableGet(m.bindings, f))
|
||||||
|
# if prev != nil:
|
||||||
|
# if sameType(prev, a): return arg
|
||||||
|
# else: return nil
|
||||||
|
|
||||||
|
# pushInfoContext(arg.info)
|
||||||
|
openScope(c)
|
||||||
|
inc c.inTypeClass
|
||||||
|
|
||||||
|
finally:
|
||||||
|
dec c.inTypeClass
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
|
if ff.kind == tyUserTypeClassInst:
|
||||||
|
for i in 1 .. <(ff.len - 1):
|
||||||
|
var
|
||||||
|
typeParamName = ff.base.sons[i-1].sym.name
|
||||||
|
typ = ff.sons[i]
|
||||||
|
param = newSym(skType, typeParamName, body.sym, body.sym.info)
|
||||||
|
|
||||||
|
param.typ = makeTypeDesc(c, typ)
|
||||||
|
addDecl(c, param)
|
||||||
|
|
||||||
|
for param in body.n[0]:
|
||||||
|
var
|
||||||
|
dummyName: PNode
|
||||||
|
dummyType: PType
|
||||||
|
|
||||||
|
if param.kind == nkVarTy:
|
||||||
|
dummyName = param[0]
|
||||||
|
dummyType = makeVarType(c, a)
|
||||||
|
else:
|
||||||
|
dummyName = param
|
||||||
|
dummyType = a
|
||||||
|
|
||||||
|
internalAssert dummyName.kind == nkIdent
|
||||||
|
var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info)
|
||||||
|
dummyParam.typ = dummyType
|
||||||
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
|
var checkedBody = c.semTryExpr(c, copyTree(body.n[3]), bufferErrors = false)
|
||||||
|
m.errors = bufferedMsgs
|
||||||
|
clearBufferedMsgs()
|
||||||
|
if checkedBody == nil: return isNone
|
||||||
|
|
||||||
|
if checkedBody.kind == nkStmtList:
|
||||||
|
for stmt in checkedBody:
|
||||||
|
case stmt.kind
|
||||||
|
of nkReturnStmt: discard
|
||||||
|
of nkTypeSection: discard
|
||||||
|
of nkConstDef: discard
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
return isGeneric
|
||||||
|
# put(m.bindings, f, a)
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
#
|
#
|
||||||
|
|
@ -418,6 +482,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
result = isNone
|
result = isNone
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
|
|
||||||
|
if f.kind == tyExpr:
|
||||||
|
put(c.bindings, f, aOrig)
|
||||||
|
return isGeneric
|
||||||
|
|
||||||
assert(aOrig != nil)
|
assert(aOrig != nil)
|
||||||
|
|
||||||
# var and static arguments match regular modifier-free types
|
# var and static arguments match regular modifier-free types
|
||||||
|
|
@ -751,6 +820,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
||||||
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
|
considerPreviousT:
|
||||||
|
result = matchUserTypeClass(c.c, c, f, a)
|
||||||
|
if result == isGeneric:
|
||||||
|
put(c.bindings, f, a)
|
||||||
|
|
||||||
of tyCompositeTypeClass:
|
of tyCompositeTypeClass:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
if typeRel(c, f.sons[1], a) != isNone:
|
if typeRel(c, f.sons[1], a) != isNone:
|
||||||
|
|
@ -759,7 +834,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
if c.calleeSym != nil and c.calleeSym.kind == skType and
|
if c.calleeSym != nil and c.calleeSym.kind == skType and
|
||||||
|
|
@ -822,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else: a.sons[0]
|
else: a.sons[0]
|
||||||
result = typeRel(c, prev.sons[0], toMatch)
|
result = typeRel(c, prev.sons[0], toMatch)
|
||||||
|
|
||||||
of tyExpr, tyStmt:
|
of tyStmt:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
|
|
@ -904,57 +979,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||||
m.baseTypeMatch = true
|
m.baseTypeMatch = true
|
||||||
|
|
||||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|
||||||
arg: PNode, f, a: PType): PNode =
|
|
||||||
if f.n == nil:
|
|
||||||
let r = typeRel(m, f, a)
|
|
||||||
return if r == isGeneric: arg else: nil
|
|
||||||
|
|
||||||
var prev = PType(idTableGet(m.bindings, f))
|
|
||||||
if prev != nil:
|
|
||||||
if sameType(prev, a): return arg
|
|
||||||
else: return nil
|
|
||||||
|
|
||||||
# pushInfoContext(arg.info)
|
|
||||||
openScope(c)
|
|
||||||
inc c.inTypeClass
|
|
||||||
|
|
||||||
finally:
|
|
||||||
dec c.inTypeClass
|
|
||||||
closeScope(c)
|
|
||||||
|
|
||||||
for param in f.n[0]:
|
|
||||||
var
|
|
||||||
dummyName: PNode
|
|
||||||
dummyType: PType
|
|
||||||
|
|
||||||
if param.kind == nkVarTy:
|
|
||||||
dummyName = param[0]
|
|
||||||
dummyType = makeVarType(c, a)
|
|
||||||
else:
|
|
||||||
dummyName = param
|
|
||||||
dummyType = a
|
|
||||||
|
|
||||||
internalAssert dummyName.kind == nkIdent
|
|
||||||
var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
|
|
||||||
dummyParam.typ = dummyType
|
|
||||||
addDecl(c, dummyParam)
|
|
||||||
|
|
||||||
for stmt in f.n[3]:
|
|
||||||
var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
|
|
||||||
m.errors = bufferedMsgs
|
|
||||||
clearBufferedMsgs()
|
|
||||||
if e == nil: return nil
|
|
||||||
|
|
||||||
case e.kind
|
|
||||||
of nkReturnStmt: discard
|
|
||||||
of nkTypeSection: discard
|
|
||||||
of nkConstDef: discard
|
|
||||||
else: discard
|
|
||||||
|
|
||||||
result = arg
|
|
||||||
put(m.bindings, f, a)
|
|
||||||
|
|
||||||
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -975,25 +999,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argType = arg.typ
|
argType = arg.typ
|
||||||
|
|
||||||
var
|
var
|
||||||
r: TTypeRelation
|
|
||||||
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc})
|
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc})
|
||||||
else: argType
|
else: argType
|
||||||
|
|
||||||
case fMaybeStatic.kind
|
|
||||||
of tyTypeClass, tyParametricTypeClass:
|
|
||||||
if fMaybeStatic.n != nil:
|
|
||||||
let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
|
|
||||||
if match != nil:
|
|
||||||
r = isGeneric
|
|
||||||
arg = match
|
|
||||||
else:
|
|
||||||
r = isNone
|
|
||||||
else:
|
|
||||||
r = typeRel(m, f, a)
|
|
||||||
of tyExpr:
|
|
||||||
r = isGeneric
|
|
||||||
put(m.bindings, f, arg.typ)
|
|
||||||
else:
|
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
case r
|
case r
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,8 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||||
result[1] = ri
|
result[1] = ri
|
||||||
|
|
||||||
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||||
if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
|
#if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
|
||||||
return liftIterSym(n)
|
# return liftIterSym(n)
|
||||||
var b: PNode
|
var b: PNode
|
||||||
var tc = c.transCon
|
var tc = c.transCon
|
||||||
if sfBorrow in n.sym.flags:
|
if sfBorrow in n.sym.flags:
|
||||||
|
|
@ -389,7 +389,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
of tyGenericParam, tyOrdinal, tyTypeClass:
|
of tyGenericParam, tyOrdinal:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
# happens sometimes for generated assignments, etc.
|
# happens sometimes for generated assignments, etc.
|
||||||
else:
|
else:
|
||||||
|
|
@ -636,6 +636,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
s.ast.sons[bodyPos] = n.sons[bodyPos]
|
s.ast.sons[bodyPos] = n.sons[bodyPos]
|
||||||
#n.sons[bodyPos] = liftLambdas(s, n)
|
#n.sons[bodyPos] = liftLambdas(s, n)
|
||||||
#if n.kind == nkMethodDef: methodDef(s, false)
|
#if n.kind == nkMethodDef: methodDef(s, false)
|
||||||
|
#if n.kind == nkIteratorDef and n.typ != nil:
|
||||||
|
# return liftIterSym(n.sons[namePos]).PTransNode
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkMacroDef:
|
of nkMacroDef:
|
||||||
# XXX no proper closure support yet:
|
# XXX no proper closure support yet:
|
||||||
|
|
@ -708,6 +710,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
# XXX comment handling really sucks:
|
# XXX comment handling really sucks:
|
||||||
if importantComments():
|
if importantComments():
|
||||||
PNode(result).comment = n.comment
|
PNode(result).comment = n.comment
|
||||||
|
of nkClosure: return PTransNode(n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
var cnst = getConstExpr(c.module, PNode(result))
|
var cnst = getConstExpr(c.module, PNode(result))
|
||||||
|
|
@ -738,8 +741,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n, prc)
|
result = processTransf(c, n, prc)
|
||||||
result = liftLambdas(prc, result)
|
result = liftLambdas(prc, result)
|
||||||
if prc.kind == skIterator and prc.typ.callConv == ccClosure:
|
#if prc.kind == skIterator and prc.typ.callConv == ccClosure:
|
||||||
result = lambdalifting.liftIterator(prc, result)
|
# result = lambdalifting.liftIterator(prc, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
when useEffectSystem: trackProc(prc, result)
|
when useEffectSystem: trackProc(prc, result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -404,9 +404,10 @@ const
|
||||||
"float", "float32", "float64", "float128",
|
"float", "float32", "float64", "float128",
|
||||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||||
"bignum", "const ",
|
"bignum", "const ",
|
||||||
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
|
"!", "varargs[$1]", "iter[$1]", "Error Type",
|
||||||
"ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass",
|
"BuiltInTypeClass", "UserTypeClass",
|
||||||
"and", "or", "not", "any", "static", "TypeFromExpr"]
|
"UserTypeClassInst", "CompositeTypeClass",
|
||||||
|
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
|
||||||
|
|
||||||
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
var t = typ
|
var t = typ
|
||||||
|
|
@ -434,11 +435,30 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
internalAssert t.len > 0
|
internalAssert t.len > 0
|
||||||
result = "static[" & typeToString(t.sons[0]) & "]"
|
result = "static[" & typeToString(t.sons[0]) & "]"
|
||||||
of tyTypeClass:
|
of tyUserTypeClass:
|
||||||
internalAssert t.sym != nil and t.sym.owner != nil
|
internalAssert t.sym != nil and t.sym.owner != nil
|
||||||
return t.sym.owner.name.s
|
return t.sym.owner.name.s
|
||||||
of tyBuiltInTypeClass:
|
of tyBuiltInTypeClass:
|
||||||
return "TypeClass"
|
result = case t.base.kind:
|
||||||
|
of tyVar: "var"
|
||||||
|
of tyRef: "ref"
|
||||||
|
of tyPtr: "ptr"
|
||||||
|
of tySequence: "seq"
|
||||||
|
of tyArray: "array"
|
||||||
|
of tySet: "set"
|
||||||
|
of tyRange: "range"
|
||||||
|
of tyDistinct: "distinct"
|
||||||
|
of tyProc: "proc"
|
||||||
|
of tyObject: "object"
|
||||||
|
of tyTuple: "tuple"
|
||||||
|
else: (internalAssert false; "")
|
||||||
|
of tyUserTypeClassInst:
|
||||||
|
let body = t.base
|
||||||
|
result = body.sym.name.s & "["
|
||||||
|
for i in countup(1, sonsLen(t) - 2):
|
||||||
|
if i > 1: add(result, ", ")
|
||||||
|
add(result, typeToString(t.sons[i]))
|
||||||
|
result.add "]"
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
|
result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
|
||||||
of tyOr:
|
of tyOr:
|
||||||
|
|
@ -448,7 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
internalAssert t.len == 0
|
internalAssert t.len == 0
|
||||||
result = "expr"
|
result = "expr"
|
||||||
of tyFromExpr:
|
of tyFromExpr, tyFieldAccessor:
|
||||||
result = renderTree(t.n)
|
result = renderTree(t.n)
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if t.sons[0].kind == tyRange:
|
if t.sons[0].kind == tyRange:
|
||||||
|
|
@ -546,7 +566,8 @@ proc firstOrd(t: PType): BiggestInt =
|
||||||
else:
|
else:
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
result = t.n.sons[0].sym.position
|
result = t.n.sons[0].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
|
of tyGenericInst, tyDistinct, tyConst, tyMutable,
|
||||||
|
tyTypeDesc, tyFieldAccessor:
|
||||||
result = firstOrd(lastSon(t))
|
result = firstOrd(lastSon(t))
|
||||||
else:
|
else:
|
||||||
internalError("invalid kind for first(" & $t.kind & ')')
|
internalError("invalid kind for first(" & $t.kind & ')')
|
||||||
|
|
@ -579,7 +600,8 @@ proc lastOrd(t: PType): BiggestInt =
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
|
of tyGenericInst, tyDistinct, tyConst, tyMutable,
|
||||||
|
tyTypeDesc, tyFieldAccessor:
|
||||||
result = lastOrd(lastSon(t))
|
result = lastOrd(lastSon(t))
|
||||||
of tyProxy: result = 0
|
of tyProxy: result = 0
|
||||||
else:
|
else:
|
||||||
|
|
@ -875,9 +897,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
of tyGenericInvokation, tyGenericBody, tySequence,
|
of tyGenericInvokation, tyGenericBody, tySequence,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||||
tyOrdinal, tyTypeClasses:
|
tyOrdinal, tyTypeClasses, tyFieldAccessor:
|
||||||
cycleCheck()
|
cycleCheck()
|
||||||
if a.kind == tyTypeClass and a.n != nil: return a.n == b.n
|
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
|
||||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
if result and a.kind == tyProc:
|
if result and a.kind == tyProc:
|
||||||
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
|
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
|
||||||
|
|
@ -1021,7 +1043,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
result = true
|
result = true
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
||||||
tyNone, tyForward, tyFromExpr:
|
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
||||||
result = false
|
result = false
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = kind == skConst
|
result = kind == skConst
|
||||||
|
|
@ -1231,8 +1253,15 @@ proc getSize(typ: PType): BiggestInt =
|
||||||
if result < 0: internalError("getSize: " & $typ.kind)
|
if result < 0: internalError("getSize: " & $typ.kind)
|
||||||
|
|
||||||
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
||||||
result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or
|
if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
|
||||||
t.kind == tyStatic and t.n == nil
|
return true
|
||||||
|
|
||||||
|
if t.kind == tyTypeDesc:
|
||||||
|
if t.sonsLen == 0: return true
|
||||||
|
if containsGenericTypeIter(t.base, closure): return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
return t.kind == tyStatic and t.n == nil
|
||||||
|
|
||||||
proc containsGenericType*(t: PType): bool =
|
proc containsGenericType*(t: PType): bool =
|
||||||
result = iterOverType(t, containsGenericTypeIter, nil)
|
result = iterOverType(t, containsGenericTypeIter, nil)
|
||||||
|
|
|
||||||
|
|
@ -802,7 +802,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
|
||||||
let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
|
let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
|
||||||
let t2 = c.types[regs[rc].intVal.int]
|
let t2 = c.types[regs[rc].intVal.int]
|
||||||
# XXX: This should use the standard isOpImpl
|
# XXX: This should use the standard isOpImpl
|
||||||
let match = if t2.kind == tyTypeClass: true
|
let match = if t2.kind == tyUserTypeClass: true
|
||||||
else: sameType(t1, t2)
|
else: sameType(t1, t2)
|
||||||
regs[ra].intVal = ord(match)
|
regs[ra].intVal = ord(match)
|
||||||
of opcSetLenSeq:
|
of opcSetLenSeq:
|
||||||
|
|
@ -1057,6 +1057,7 @@ proc fixType(result, n: PNode) {.inline.} =
|
||||||
# XXX do it deeply for complex values; there seems to be no simple
|
# XXX do it deeply for complex values; there seems to be no simple
|
||||||
# solution except to check it deeply here.
|
# solution except to check it deeply here.
|
||||||
#if result.typ.isNil: result.typ = n.typ
|
#if result.typ.isNil: result.typ = n.typ
|
||||||
|
discard
|
||||||
|
|
||||||
proc execute(c: PCtx, start: int): PNode =
|
proc execute(c: PCtx, start: int): PNode =
|
||||||
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
||||||
|
|
@ -1118,6 +1119,7 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
||||||
var c = globalCtx
|
var c = globalCtx
|
||||||
c.mode = mode
|
c.mode = mode
|
||||||
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
|
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
|
||||||
|
if c.code[start].opcode == opcEof: return emptyNode
|
||||||
assert c.code[start].opcode != opcEof
|
assert c.code[start].opcode != opcEof
|
||||||
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
|
|
|
||||||
192
doc/docgen.txt
Normal file
192
doc/docgen.txt
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
===================================
|
||||||
|
Nimrod DocGen Tools Guide
|
||||||
|
===================================
|
||||||
|
|
||||||
|
:Author: Erik O'Leary
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document describes the `documentation generation tools`:idx: built into
|
||||||
|
the `Nimrod compiler <nimrodc.html>`_, which can generate HTML and JSON output
|
||||||
|
from input .nim files and projects, as well as HTML and LaTeX from input RST
|
||||||
|
(reStructuredText) files. The output documentation will include module
|
||||||
|
dependencies (``import``), any top-level documentation comments (##), and
|
||||||
|
exported symbols (*), including procedures, types, and variables.
|
||||||
|
|
||||||
|
|
||||||
|
Documentation Comments
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Any comments which are preceded by a double-hash (##), are interpreted as
|
||||||
|
documentation. Comments are parsed as RST (see `reference
|
||||||
|
<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_), providing
|
||||||
|
Nimrod module authors the ability to easily generate richly formatted
|
||||||
|
documentation with only their well-documented code.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type TPerson* = object
|
||||||
|
## This type contains a description of a person
|
||||||
|
name: string
|
||||||
|
age: int
|
||||||
|
|
||||||
|
Outputs::
|
||||||
|
TPerson* = object
|
||||||
|
name: string
|
||||||
|
age: int
|
||||||
|
|
||||||
|
This type contains a description of a person
|
||||||
|
|
||||||
|
Field documentation comments can be added to fields like so:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
var numValues: int ## \
|
||||||
|
## `numValues` stores the number of values
|
||||||
|
|
||||||
|
Note that without the `*` following the name of the type, the documentation for
|
||||||
|
this type would not be generated. Documentation will only be generated for
|
||||||
|
*exported* types/procedures/etc.
|
||||||
|
|
||||||
|
|
||||||
|
Nimrod file input
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The following examples will generate documentation for the below contrived
|
||||||
|
*Nimrod* module, aptly named 'sample.nim'
|
||||||
|
|
||||||
|
sample.nim:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
## This module is a sample.
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
proc helloWorld*(times: int) =
|
||||||
|
## Takes an integer and outputs
|
||||||
|
## as many "hello world!"s
|
||||||
|
|
||||||
|
for i in 0 .. times-1:
|
||||||
|
echo "hello world!"
|
||||||
|
|
||||||
|
helloWorld(5)
|
||||||
|
|
||||||
|
|
||||||
|
Document Types
|
||||||
|
==============
|
||||||
|
|
||||||
|
|
||||||
|
HTML
|
||||||
|
----
|
||||||
|
|
||||||
|
Generation of HTML documents is done via both the ``doc`` and ``doc2``
|
||||||
|
commands. These command take either a single .nim file, outputting a single
|
||||||
|
.html file with the same base filename, or multiple .nim files, outputting
|
||||||
|
multiple .html files and, optionally, an index file.
|
||||||
|
|
||||||
|
The ``doc`` command::
|
||||||
|
nimrod doc sample
|
||||||
|
|
||||||
|
Partial Output::
|
||||||
|
...
|
||||||
|
proc helloWorld*(times: int)
|
||||||
|
...
|
||||||
|
|
||||||
|
Output can be viewed in full here: `docgen_sample.html <docgen_sample.html>`_.
|
||||||
|
The next command, called ``doc2``, is very similar to the ``doc`` command, but
|
||||||
|
will be run after the compiler performs semantic checking on the input nimrod
|
||||||
|
module(s), which allows it to process macros.
|
||||||
|
|
||||||
|
The ``doc2`` command::
|
||||||
|
nimrod doc2 sample
|
||||||
|
|
||||||
|
Partial Output::
|
||||||
|
...
|
||||||
|
proc helloWorld(times: int) {.raises: [], tags: [].}
|
||||||
|
...
|
||||||
|
|
||||||
|
The full output can be seen here: `docgen_sample2.html <docgen_sample2.html>`_.
|
||||||
|
As you can see, the tool has extracted additional information provided to it by
|
||||||
|
the compiler beyond what the ``doc`` command provides, such as pragmas attached
|
||||||
|
implicitly by the compiler. This type of information is not available from
|
||||||
|
looking at the AST (Abstract Syntax Tree) prior to semantic checking, as the
|
||||||
|
``doc`` command does.
|
||||||
|
|
||||||
|
|
||||||
|
JSON
|
||||||
|
----
|
||||||
|
|
||||||
|
Generation of JSON documents is done via the ``jsondoc`` command. This command
|
||||||
|
takes in a .nim file, and outputs a .json file with the same base filename.
|
||||||
|
Note that this tool is built off of the ``doc`` command, and therefore is
|
||||||
|
performed before semantic checking.
|
||||||
|
|
||||||
|
The ``jsondoc`` command::
|
||||||
|
nimrod jsondoc sample
|
||||||
|
|
||||||
|
Output::
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"comment": "This module is a sample."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "helloWorld",
|
||||||
|
"type": "skProc",
|
||||||
|
"description": "Takes an integer and outputs as many "hello world!"s",
|
||||||
|
"code": "proc helloWorld*(times: int)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Related Options
|
||||||
|
===============
|
||||||
|
|
||||||
|
``--project`` switch
|
||||||
|
::
|
||||||
|
nimrod doc2 --project sample
|
||||||
|
|
||||||
|
This will recursively generate documentation of all nimrod modules imported
|
||||||
|
into the input module, including system modules. Be careful with this command,
|
||||||
|
as it may end up sprinkling html files all over your filesystem!
|
||||||
|
|
||||||
|
|
||||||
|
``--index`` switch
|
||||||
|
::
|
||||||
|
nimrod doc2 --index:on sample
|
||||||
|
|
||||||
|
This will generate an index of all the exported symbols in the input Nimrod
|
||||||
|
module, and put it into a neighboring file with the extension of `.idx`.
|
||||||
|
|
||||||
|
|
||||||
|
Other Input Formats
|
||||||
|
===================
|
||||||
|
|
||||||
|
The *Nimrod compiler* also has support for RST (reStructuredText) files with
|
||||||
|
the ``rst2html`` and ``rst2tex`` commands. Documents like this one are
|
||||||
|
initially written in a dialect of RST which adds support for nimrod sourcecode
|
||||||
|
highlighting with the ``.. code-block:: nimrod`` prefix. ``code-block`` also
|
||||||
|
supports highlighting of C++ and some other c-like languages.
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
nimrod rst2html docgen.txt
|
||||||
|
|
||||||
|
Output::
|
||||||
|
You're reading it!
|
||||||
|
|
||||||
|
The input can be viewed here `docgen.txt <docgen.txt>`_. The ``rst2tex``
|
||||||
|
command is invoked identically to ``rst2html``, but outputs a .tex file instead
|
||||||
|
of .html.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Resources
|
||||||
|
=========
|
||||||
|
|
||||||
|
`Nimrod Compiler User Guide <nimrodc.html#command-line-switches>`_
|
||||||
|
|
||||||
|
`RST Quick Reference
|
||||||
|
<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
|
||||||
12
doc/docgen_sample.nim
Normal file
12
doc/docgen_sample.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
## This module is a sample.
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
proc helloWorld*(times: int) =
|
||||||
|
## Takes an integer and outputs
|
||||||
|
## as many "hello world!"s
|
||||||
|
|
||||||
|
for i in 0 .. times-1:
|
||||||
|
echo "hello world!"
|
||||||
|
|
||||||
|
helloWorld(5)
|
||||||
|
|
@ -42,14 +42,14 @@ par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
|
||||||
| simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
|
| simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
|
||||||
| (':' expr)? (',' (exprColonEqExpr comma?)*)? )?
|
| (':' expr)? (',' (exprColonEqExpr comma?)*)? )?
|
||||||
optPar ')'
|
optPar ')'
|
||||||
|
literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
|
| UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||||
|
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||||
|
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
|
| CHAR_LIT
|
||||||
|
| NIL
|
||||||
generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||||
identOrLiteral = generalizedLit | symbol
|
identOrLiteral = generalizedLit | symbol | literal
|
||||||
| INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
|
||||||
| UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
|
||||||
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
|
||||||
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
|
||||||
| CHAR_LIT
|
|
||||||
| NIL
|
|
||||||
| par | arrayConstr | setOrTableConstr
|
| par | arrayConstr | setOrTableConstr
|
||||||
| castExpr
|
| castExpr
|
||||||
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||||
|
|
@ -59,6 +59,8 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
| '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
| '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
||||||
| '[' optInd indexExprList optPar ']'
|
| '[' optInd indexExprList optPar ']'
|
||||||
| '{' optInd indexExprList optPar '}'
|
| '{' optInd indexExprList optPar '}'
|
||||||
|
| &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
|
||||||
|
(doBlock | macroColon)?
|
||||||
condExpr = expr colcom expr optInd
|
condExpr = expr colcom expr optInd
|
||||||
('elif' expr colcom expr optInd)*
|
('elif' expr colcom expr optInd)*
|
||||||
'else' colcom expr
|
'else' colcom expr
|
||||||
|
|
@ -95,18 +97,19 @@ primary = typeKeyw typeDescK
|
||||||
/ 'bind' primary
|
/ 'bind' primary
|
||||||
typeDesc = simpleExpr
|
typeDesc = simpleExpr
|
||||||
typeDefAux = simpleExpr
|
typeDefAux = simpleExpr
|
||||||
|
| 'generic' typeClass
|
||||||
|
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||||
|
| IND{=} 'elif' expr ':' stmt
|
||||||
|
| IND{=} 'except' exprList ':' stmt
|
||||||
|
| IND{=} 'else' ':' stmt )*
|
||||||
exprStmt = simpleExpr
|
exprStmt = simpleExpr
|
||||||
(( '=' optInd expr )
|
(( '=' optInd expr )
|
||||||
/ ( expr ^+ comma
|
/ ( expr ^+ comma
|
||||||
doBlocks
|
doBlocks
|
||||||
/ ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
/ macroColon
|
||||||
| IND{=} 'elif' expr ':' stmt
|
|
||||||
| IND{=} 'except' exprList ':' stmt
|
|
||||||
| IND{=} 'else' ':' stmt )*
|
|
||||||
))?
|
))?
|
||||||
moduleName = expr ('as' expr)?
|
importStmt = 'import' optInd expr
|
||||||
importStmt = 'import' optInd moduleName
|
((comma expr)*
|
||||||
((comma moduleName)*
|
|
||||||
/ 'except' optInd (expr ^+ comma))
|
/ 'except' optInd (expr ^+ comma))
|
||||||
includeStmt = 'include' optInd expr ^+ comma
|
includeStmt = 'include' optInd expr ^+ comma
|
||||||
fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
|
fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
|
||||||
|
|
@ -161,6 +164,9 @@ objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
|
||||||
objectPart = IND{>} objectPart^+IND{=} DED
|
objectPart = IND{>} objectPart^+IND{=} DED
|
||||||
/ objectWhen / objectCase / 'nil' / declColonEquals
|
/ objectWhen / objectCase / 'nil' / declColonEquals
|
||||||
object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
|
object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
|
||||||
|
typeClassParam = ('var')? symbol
|
||||||
|
typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||||
|
&IND{>} stmt
|
||||||
distinct = 'distinct' optInd typeDesc
|
distinct = 'distinct' optInd typeDesc
|
||||||
typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
|
typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
|
||||||
indAndComment?
|
indAndComment?
|
||||||
|
|
|
||||||
|
|
@ -2261,8 +2261,8 @@ from different modules having the same name.
|
||||||
using sdl.SetTimer
|
using sdl.SetTimer
|
||||||
|
|
||||||
Note that ``using`` only *adds* to the current context, it doesn't remove or
|
Note that ``using`` only *adds* to the current context, it doesn't remove or
|
||||||
replace, **neither** does it create a new scope. What this means is that if you
|
replace, **neither** does it create a new scope. What this means is that if one
|
||||||
apply this to multiple variables the compiler will find conflicts in what
|
applies this to multiple variables the compiler will find conflicts in what
|
||||||
variable to use:
|
variable to use:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -2275,7 +2275,7 @@ variable to use:
|
||||||
echo b
|
echo b
|
||||||
|
|
||||||
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
|
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
|
||||||
be used with the proc, so you get ``Error: expression '(a|b)' has no type (or
|
be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
|
||||||
is ambiguous)``. To solve this you would need to nest ``using`` with a
|
is ambiguous)``. To solve this you would need to nest ``using`` with a
|
||||||
``block`` statement so as to control the reach of the ``using`` statement.
|
``block`` statement so as to control the reach of the ``using`` statement.
|
||||||
|
|
||||||
|
|
@ -2368,8 +2368,8 @@ The `addr`:idx: operator returns the address of an l-value. If the type of the
|
||||||
location is ``T``, the `addr` operator result is of the type ``ptr T``. An
|
location is ``T``, the `addr` operator result is of the type ``ptr T``. An
|
||||||
address is always an untraced reference. Taking the address of an object that
|
address is always an untraced reference. Taking the address of an object that
|
||||||
resides on the stack is **unsafe**, as the pointer may live longer than the
|
resides on the stack is **unsafe**, as the pointer may live longer than the
|
||||||
object on the stack and can thus reference a non-existing object. You can get
|
object on the stack and can thus reference a non-existing object. One can get
|
||||||
the address of variables, but you can't use it on variables declared through
|
the address of variables, but one can't use it on variables declared through
|
||||||
``let`` statements:
|
``let`` statements:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -2764,7 +2764,7 @@ First class iterators
|
||||||
There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
|
There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
|
||||||
An `inline iterator`:idx: is an iterator that's always inlined by the compiler
|
An `inline iterator`:idx: is an iterator that's always inlined by the compiler
|
||||||
leading to zero overhead for the abstraction, but may result in a heavy
|
leading to zero overhead for the abstraction, but may result in a heavy
|
||||||
increasee in code size. Inline iterators are second class
|
increase in code size. Inline iterators are second class
|
||||||
citizens; one cannot pass them around like first class procs.
|
citizens; one cannot pass them around like first class procs.
|
||||||
|
|
||||||
In contrast to that, a `closure iterator`:idx: can be passed around:
|
In contrast to that, a `closure iterator`:idx: can be passed around:
|
||||||
|
|
@ -2837,6 +2837,23 @@ The builtin ``system.finished`` can be used to determine if an iterator has
|
||||||
finished its operation; no exception is raised on an attempt to invoke an
|
finished its operation; no exception is raised on an attempt to invoke an
|
||||||
iterator that has already finished its work.
|
iterator that has already finished its work.
|
||||||
|
|
||||||
|
Closure iterators are *resumable functions* and so one has to provide the
|
||||||
|
arguments to every call. To get around this limitation one can capture
|
||||||
|
parameters of an outer factory proc:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc mycount(a, b: int): iterator (): int =
|
||||||
|
return iterator (): int =
|
||||||
|
var x = a
|
||||||
|
while x <= b:
|
||||||
|
yield x
|
||||||
|
inc x
|
||||||
|
|
||||||
|
let foo = mycount 1, 4
|
||||||
|
|
||||||
|
for f in foo():
|
||||||
|
echo f
|
||||||
|
|
||||||
|
|
||||||
Type sections
|
Type sections
|
||||||
=============
|
=============
|
||||||
|
|
@ -2923,9 +2940,9 @@ in an implicit try block:
|
||||||
finally: close(f)
|
finally: close(f)
|
||||||
...
|
...
|
||||||
|
|
||||||
The ``except`` statement has a limitation in this form: you can't specify the
|
The ``except`` statement has a limitation in this form: one can't specify the
|
||||||
type of the exception, you have to catch everything. Also, if you want to use
|
type of the exception, one has to catch everything. Also, if one wants to use
|
||||||
both ``finally`` and ``except`` you need to reverse the usual sequence of the
|
both ``finally`` and ``except`` one needs to reverse the usual sequence of the
|
||||||
statements. Example:
|
statements. Example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -3353,7 +3370,7 @@ currently matched type. These instances can act both as variables of the type,
|
||||||
when used in contexts, where a value is expected, and as the type itself, when
|
when used in contexts, where a value is expected, and as the type itself, when
|
||||||
used in a contexts, where a type is expected.
|
used in a contexts, where a type is expected.
|
||||||
|
|
||||||
Please note that the ``is`` operator allows you to easily verify the precise
|
Please note that the ``is`` operator allows one to easily verify the precise
|
||||||
type signatures of the required operations, but since type inference and
|
type signatures of the required operations, but since type inference and
|
||||||
default parameters are still applied in the provided block, it's also possible
|
default parameters are still applied in the provided block, it's also possible
|
||||||
to encode usage protocols that doesn't reveal implementation details.
|
to encode usage protocols that doesn't reveal implementation details.
|
||||||
|
|
|
||||||
|
|
@ -538,6 +538,13 @@ on Linux::
|
||||||
nimrod c --dynlibOverride:lua --passL:liblua.lib program.nim
|
nimrod c --dynlibOverride:lua --passL:liblua.lib program.nim
|
||||||
|
|
||||||
|
|
||||||
|
Nimrod documentation tools
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Nimrod provides the `doc`:idx: and `doc2`:idx: commands to generate HTML
|
||||||
|
documentation from ``.nim`` source files. Only exported symbols will appear in
|
||||||
|
the output. For more details `see the docgen documentation <docgen.html>`_.
|
||||||
|
|
||||||
Nimrod idetools integration
|
Nimrod idetools integration
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
|
|
||||||
9
koch.nim
9
koch.nim
|
|
@ -42,7 +42,7 @@ Possible Commands:
|
||||||
csource [options] builds the C sources for installation
|
csource [options] builds the C sources for installation
|
||||||
zip builds the installation ZIP package
|
zip builds the installation ZIP package
|
||||||
inno [options] builds the Inno Setup installer (for Windows)
|
inno [options] builds the Inno Setup installer (for Windows)
|
||||||
tests run the testsuite
|
tests [options] run the testsuite
|
||||||
update updates nimrod to the latest version from github
|
update updates nimrod to the latest version from github
|
||||||
(compile koch with -d:withUpdate to enable)
|
(compile koch with -d:withUpdate to enable)
|
||||||
temp options creates a temporary compiler for testing
|
temp options creates a temporary compiler for testing
|
||||||
|
|
@ -260,11 +260,14 @@ when defined(withUpdate):
|
||||||
|
|
||||||
# -------------- tests --------------------------------------------------------
|
# -------------- tests --------------------------------------------------------
|
||||||
|
|
||||||
|
template `|`(a, b): expr = (if a.len > 0: a else: b)
|
||||||
|
|
||||||
proc tests(args: string) =
|
proc tests(args: string) =
|
||||||
# we compile the tester with taintMode:on to have a basic
|
# we compile the tester with taintMode:on to have a basic
|
||||||
# taint mode test :-)
|
# taint mode test :-)
|
||||||
exec("nimrod cc --taintMode:on tests/testament/tester")
|
exec "nimrod cc --taintMode:on tests/testament/tester"
|
||||||
exec(getCurrentDir() / "tests/testament/tester".exe & " all")
|
exec quoteShell(getCurrentDir() / "tests/testament/tester".exe) & " " &
|
||||||
|
(args|"all")
|
||||||
|
|
||||||
proc temp(args: string) =
|
proc temp(args: string) =
|
||||||
var output = "compiler" / "nimrod".exe
|
var output = "compiler" / "nimrod".exe
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,12 @@ when not defined(booting):
|
||||||
## that should be inserted verbatim in the program
|
## that should be inserted verbatim in the program
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||||
##
|
##
|
||||||
eval: result = e.parseStmt
|
macro payload: stmt {.gensym.} =
|
||||||
|
result = e.parseStmt
|
||||||
|
payload()
|
||||||
|
|
||||||
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
||||||
## checks that `n` is of kind `k`. If this is not the case,
|
## checks that `n` is of kind `k`. If this is not the case,
|
||||||
|
|
@ -387,7 +390,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||||
res.add(($n.kind).substr(3))
|
res.add(($n.kind).substr(3))
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: nil # same as nil node in this representation
|
of nnkEmpty: discard # same as nil node in this representation
|
||||||
of nnkNilLit: res.add(" nil")
|
of nnkNilLit: res.add(" nil")
|
||||||
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
||||||
|
|
@ -412,7 +415,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||||
add(result, "(")
|
add(result, "(")
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: nil # same as nil node in this representation
|
of nnkEmpty: discard # same as nil node in this representation
|
||||||
of nnkNilLit: add(result, "nil")
|
of nnkNilLit: add(result, "nil")
|
||||||
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
||||||
|
|
@ -645,10 +648,13 @@ iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
|
||||||
for i in 0 .. high(n):
|
for i in 0 .. high(n):
|
||||||
yield n[i]
|
yield n[i]
|
||||||
|
|
||||||
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.immediate, dirty.} =
|
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
|
||||||
## Find the first child node matching condition (or nil)
|
immediate, dirty.} =
|
||||||
## var res = findChild(n, it.kind == nnkPostfix and it.basename.ident == !"foo")
|
## Find the first child node matching condition (or nil).
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## var res = findChild(n, it.kind == nnkPostfix and
|
||||||
|
## it.basename.ident == !"foo")
|
||||||
block:
|
block:
|
||||||
var result: PNimrodNode
|
var result: PNimrodNode
|
||||||
for it in n.children:
|
for it in n.children:
|
||||||
|
|
@ -736,6 +742,6 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
|
||||||
if ident.eqIdent($node): return
|
if ident.eqIdent($node): return
|
||||||
of nnkExprColonExpr:
|
of nnkExprColonExpr:
|
||||||
if ident.eqIdent($node[0]): return
|
if ident.eqIdent($node[0]): return
|
||||||
else: nil
|
else: discard
|
||||||
dest.add(ident(ident))
|
dest.add(ident(ident))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,27 +139,27 @@ type
|
||||||
proc newDelegate*(): PDelegate =
|
proc newDelegate*(): PDelegate =
|
||||||
## Creates a new delegate.
|
## Creates a new delegate.
|
||||||
new(result)
|
new(result)
|
||||||
result.handleRead = (proc (h: PObject) = nil)
|
result.handleRead = (proc (h: PObject) = discard)
|
||||||
result.handleWrite = (proc (h: PObject) = nil)
|
result.handleWrite = (proc (h: PObject) = discard)
|
||||||
result.handleError = (proc (h: PObject) = nil)
|
result.handleError = (proc (h: PObject) = discard)
|
||||||
result.hasDataBuffered = (proc (h: PObject): bool = return false)
|
result.hasDataBuffered = (proc (h: PObject): bool = return false)
|
||||||
result.task = (proc (h: PObject) = nil)
|
result.task = (proc (h: PObject) = discard)
|
||||||
result.mode = fmRead
|
result.mode = fmRead
|
||||||
|
|
||||||
proc newAsyncSocket(): PAsyncSocket =
|
proc newAsyncSocket(): PAsyncSocket =
|
||||||
new(result)
|
new(result)
|
||||||
result.info = SockIdle
|
result.info = SockIdle
|
||||||
|
|
||||||
result.handleRead = (proc (s: PAsyncSocket) = nil)
|
result.handleRead = (proc (s: PAsyncSocket) = discard)
|
||||||
result.handleWrite = nil
|
result.handleWrite = nil
|
||||||
result.handleConnect = (proc (s: PAsyncSocket) = nil)
|
result.handleConnect = (proc (s: PAsyncSocket) = discard)
|
||||||
result.handleAccept = (proc (s: PAsyncSocket) = nil)
|
result.handleAccept = (proc (s: PAsyncSocket) = discard)
|
||||||
result.handleTask = (proc (s: PAsyncSocket) = nil)
|
result.handleTask = (proc (s: PAsyncSocket) = discard)
|
||||||
|
|
||||||
result.lineBuffer = "".TaintedString
|
result.lineBuffer = "".TaintedString
|
||||||
result.sendBuffer = ""
|
result.sendBuffer = ""
|
||||||
|
|
||||||
proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
proc asyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP,
|
protocol: TProtocol = IPPROTO_TCP,
|
||||||
buffered = true): PAsyncSocket =
|
buffered = true): PAsyncSocket =
|
||||||
## Initialises an AsyncSocket object. If a socket cannot be initialised
|
## Initialises an AsyncSocket object. If a socket cannot be initialised
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ type
|
||||||
EInvalidReply* = object of ESynch
|
EInvalidReply* = object of ESynch
|
||||||
EFTP* = object of ESynch
|
EFTP* = object of ESynch
|
||||||
|
|
||||||
proc FTPClient*(address: string, port = TPort(21),
|
proc ftpClient*(address: string, port = TPort(21),
|
||||||
user, pass = ""): PFTPClient =
|
user, pass = ""): PFTPClient =
|
||||||
## Create a ``PFTPClient`` object.
|
## Create a ``PFTPClient`` object.
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -315,7 +315,7 @@ proc listDirs*(ftp: PFTPClient, dir: string = "",
|
||||||
assertReply ftp.send("NLST " & dir.normalizePathSep), ["125", "150"]
|
assertReply ftp.send("NLST " & dir.normalizePathSep), ["125", "150"]
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
while not ftp.job.prc(ftp, false): nil
|
while not ftp.job.prc(ftp, false): discard
|
||||||
result = splitLines(ftp.job.lines)
|
result = splitLines(ftp.job.lines)
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
else: return @[]
|
else: return @[]
|
||||||
|
|
@ -390,7 +390,7 @@ proc list*(ftp: PFTPClient, dir: string = "", async = false): string =
|
||||||
assertReply(ftp.send("LIST" & " " & dir.normalizePathSep), ["125", "150"])
|
assertReply(ftp.send("LIST" & " " & dir.normalizePathSep), ["125", "150"])
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
while not ftp.job.prc(ftp, false): nil
|
while not ftp.job.prc(ftp, false): discard
|
||||||
result = ftp.job.lines
|
result = ftp.job.lines
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
else:
|
else:
|
||||||
|
|
@ -405,7 +405,7 @@ proc retrText*(ftp: PFTPClient, file: string, async = false): string =
|
||||||
assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
|
assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
while not ftp.job.prc(ftp, false): nil
|
while not ftp.job.prc(ftp, false): discard
|
||||||
result = ftp.job.lines
|
result = ftp.job.lines
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
else:
|
else:
|
||||||
|
|
@ -460,7 +460,7 @@ proc retrFile*(ftp: PFTPClient, file, dest: string, async = false) =
|
||||||
ftp.job.filename = file.normalizePathSep
|
ftp.job.filename = file.normalizePathSep
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
while not ftp.job.prc(ftp, false): nil
|
while not ftp.job.prc(ftp, false): discard
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
|
|
||||||
proc doUpload(ftp: PFTPClient, async = false): bool =
|
proc doUpload(ftp: PFTPClient, async = false): bool =
|
||||||
|
|
@ -518,7 +518,7 @@ proc store*(ftp: PFTPClient, file, dest: string, async = false) =
|
||||||
assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
|
assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
while not ftp.job.prc(ftp, false): nil
|
while not ftp.job.prc(ftp, false): discard
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
|
|
||||||
proc close*(ftp: PFTPClient) =
|
proc close*(ftp: PFTPClient) =
|
||||||
|
|
@ -554,10 +554,10 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
||||||
|
|
||||||
ftp.handleEvent(ftp, r)
|
ftp.handleEvent(ftp, r)
|
||||||
|
|
||||||
proc AsyncFTPClient*(address: string, port = TPort(21),
|
proc asyncFTPClient*(address: string, port = TPort(21),
|
||||||
user, pass = "",
|
user, pass = "",
|
||||||
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} =
|
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} =
|
||||||
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = nil)): PAsyncFTPClient =
|
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
|
||||||
## Create a ``PAsyncFTPClient`` object.
|
## Create a ``PAsyncFTPClient`` object.
|
||||||
##
|
##
|
||||||
## Use this if you want to use asyncio's dispatcher.
|
## Use this if you want to use asyncio's dispatcher.
|
||||||
|
|
@ -604,7 +604,7 @@ when isMainModule:
|
||||||
ftp.close()
|
ftp.close()
|
||||||
echo d.len
|
echo d.len
|
||||||
else: assert(false)
|
else: assert(false)
|
||||||
var ftp = AsyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
|
var ftp = asyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
|
||||||
|
|
||||||
d.register(ftp)
|
d.register(ftp)
|
||||||
d.len.echo()
|
d.len.echo()
|
||||||
|
|
@ -618,7 +618,7 @@ when isMainModule:
|
||||||
|
|
||||||
|
|
||||||
when isMainModule and false:
|
when isMainModule and false:
|
||||||
var ftp = FTPClient("picheta.me", user = "asdasd", pass = "asfwq")
|
var ftp = ftpClient("picheta.me", user = "asdasd", pass = "asfwq")
|
||||||
ftp.connect()
|
ftp.connect()
|
||||||
echo ftp.pwd()
|
echo ftp.pwd()
|
||||||
echo ftp.list()
|
echo ftp.list()
|
||||||
|
|
|
||||||
|
|
@ -1586,7 +1586,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||||
# little heuristic that may work on other POSIX-like systems:
|
# little heuristic that may work on other POSIX-like systems:
|
||||||
result = string(getEnv("_"))
|
result = string(getEnv("_"))
|
||||||
if len(result) == 0:
|
if len(result) == 0:
|
||||||
result = string(ParamStr(0))
|
result = string(paramStr(0))
|
||||||
# POSIX guaranties that this contains the executable
|
# POSIX guaranties that this contains the executable
|
||||||
# as it has been executed by the calling process
|
# as it has been executed by the calling process
|
||||||
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
||||||
|
|
|
||||||
|
|
@ -664,9 +664,8 @@ elif not defined(useNimRtl):
|
||||||
chck res
|
chck res
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
pid = fork()
|
||||||
Pid = fork()
|
if pid < 0: osError(osLastError())
|
||||||
if Pid < 0: osError(osLastError())
|
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
## child process:
|
## child process:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
|
||||||
|
|
||||||
proc spaceCost(n: TPeg): int =
|
proc spaceCost(n: TPeg): int =
|
||||||
case n.kind
|
case n.kind
|
||||||
of pkEmpty: nil
|
of pkEmpty: discard
|
||||||
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
|
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
|
||||||
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
||||||
pkAny..pkWhitespace, pkGreedyAny:
|
pkAny..pkWhitespace, pkGreedyAny:
|
||||||
|
|
@ -1117,7 +1117,7 @@ proc handleHexChar(c: var TPegLexer, xi: var int) =
|
||||||
of 'A'..'F':
|
of 'A'..'F':
|
||||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
|
proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
|
|
@ -1347,7 +1347,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
|
||||||
of "i": tok.modifier = modIgnoreCase
|
of "i": tok.modifier = modIgnoreCase
|
||||||
of "y": tok.modifier = modIgnoreStyle
|
of "y": tok.modifier = modIgnoreStyle
|
||||||
of "v": tok.modifier = modVerbatim
|
of "v": tok.modifier = modVerbatim
|
||||||
else: nil
|
else: discard
|
||||||
setLen(tok.literal, 0)
|
setLen(tok.literal, 0)
|
||||||
if c.buf[c.bufpos] == '$':
|
if c.buf[c.bufpos] == '$':
|
||||||
getDollar(c, tok)
|
getDollar(c, tok)
|
||||||
|
|
@ -1494,7 +1494,7 @@ proc primary(p: var TPegParser): TPeg =
|
||||||
of tkCurlyAt:
|
of tkCurlyAt:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
return !*\primary(p).token(p)
|
return !*\primary(p).token(p)
|
||||||
else: nil
|
else: discard
|
||||||
case p.tok.kind
|
case p.tok.kind
|
||||||
of tkIdentifier:
|
of tkIdentifier:
|
||||||
if p.identIsVerbatim:
|
if p.identIsVerbatim:
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ when defined(Posix):
|
||||||
of AF_UNIX: result = posix.AF_UNIX
|
of AF_UNIX: result = posix.AF_UNIX
|
||||||
of AF_INET: result = posix.AF_INET
|
of AF_INET: result = posix.AF_INET
|
||||||
of AF_INET6: result = posix.AF_INET6
|
of AF_INET6: result = posix.AF_INET6
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
proc toInt(typ: TType): cint =
|
proc toInt(typ: TType): cint =
|
||||||
case typ
|
case typ
|
||||||
|
|
@ -200,7 +200,7 @@ when defined(Posix):
|
||||||
of SOCK_DGRAM: result = posix.SOCK_DGRAM
|
of SOCK_DGRAM: result = posix.SOCK_DGRAM
|
||||||
of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
|
of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
|
||||||
of SOCK_RAW: result = posix.SOCK_RAW
|
of SOCK_RAW: result = posix.SOCK_RAW
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
proc toInt(p: TProtocol): cint =
|
proc toInt(p: TProtocol): cint =
|
||||||
case p
|
case p
|
||||||
|
|
@ -210,7 +210,7 @@ when defined(Posix):
|
||||||
of IPPROTO_IPV6: result = posix.IPPROTO_IPV6
|
of IPPROTO_IPV6: result = posix.IPPROTO_IPV6
|
||||||
of IPPROTO_RAW: result = posix.IPPROTO_RAW
|
of IPPROTO_RAW: result = posix.IPPROTO_RAW
|
||||||
of IPPROTO_ICMP: result = posix.IPPROTO_ICMP
|
of IPPROTO_ICMP: result = posix.IPPROTO_ICMP
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
else:
|
else:
|
||||||
proc toInt(domain: TDomain): cint =
|
proc toInt(domain: TDomain): cint =
|
||||||
|
|
|
||||||
|
|
@ -447,38 +447,38 @@ proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.}
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# built-in operators
|
# built-in operators
|
||||||
|
|
||||||
proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
|
when not defined(JS):
|
||||||
## zero extends a smaller integer type to ``int``. This treats `x` as
|
proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
|
||||||
## unsigned.
|
## zero extends a smaller integer type to ``int``. This treats `x` as
|
||||||
proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
|
## unsigned.
|
||||||
## zero extends a smaller integer type to ``int``. This treats `x` as
|
proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
|
||||||
## unsigned.
|
## zero extends a smaller integer type to ``int``. This treats `x` as
|
||||||
|
## unsigned.
|
||||||
|
|
||||||
proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
|
proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
|
||||||
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
||||||
## unsigned.
|
## unsigned.
|
||||||
proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
|
proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
|
||||||
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
||||||
## unsigned.
|
## unsigned.
|
||||||
|
|
||||||
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
|
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
|
||||||
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
||||||
## unsigned.
|
## unsigned.
|
||||||
proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
|
proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
|
||||||
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
## zero extends a smaller integer type to ``int64``. This treats `x` as
|
||||||
## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
|
## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
|
||||||
## (This is the case on 64 bit processors.)
|
## (This is the case on 64 bit processors.)
|
||||||
|
|
||||||
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
|
||||||
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
|
||||||
## from `x`.
|
|
||||||
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
|
||||||
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
|
||||||
## 16 bits from `x`.
|
|
||||||
proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
|
|
||||||
## treats `x` as unsigned and converts it to an ``int32`` by taking the
|
|
||||||
## last 32 bits from `x`.
|
|
||||||
|
|
||||||
|
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
||||||
|
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
||||||
|
## from `x`.
|
||||||
|
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
||||||
|
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
||||||
|
## 16 bits from `x`.
|
||||||
|
proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
|
||||||
|
## treats `x` as unsigned and converts it to an ``int32`` by taking the
|
||||||
|
## last 32 bits from `x`.
|
||||||
|
|
||||||
# integer calculations:
|
# integer calculations:
|
||||||
proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
|
proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
|
||||||
|
|
@ -1330,7 +1330,7 @@ iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
|
||||||
## such isn't aware of the parallelism in your code! Be careful! Later
|
## such isn't aware of the parallelism in your code! Be careful! Later
|
||||||
## versions of ``||`` will get proper support by Nimrod's code generator
|
## versions of ``||`` will get proper support by Nimrod's code generator
|
||||||
## and GC.
|
## and GC.
|
||||||
nil
|
discard
|
||||||
|
|
||||||
{.push stackTrace:off.}
|
{.push stackTrace:off.}
|
||||||
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} =
|
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} =
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
# use the heap (and nor exceptions) do not include the GC or memory allocator.
|
# use the heap (and nor exceptions) do not include the GC or memory allocator.
|
||||||
|
|
||||||
var
|
var
|
||||||
errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
|
errorMessageWriter*: (proc(msg: string) {.tags: [FWriteIO].})
|
||||||
## Function that will be called
|
## Function that will be called
|
||||||
## instead of stdmsg.write when printing stacktrace.
|
## instead of stdmsg.write when printing stacktrace.
|
||||||
## Unstable API.
|
## Unstable API.
|
||||||
|
|
@ -80,9 +80,9 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||||
type
|
type
|
||||||
TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
|
TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
|
||||||
final, pure.} = object
|
final, pure.} = object
|
||||||
dli_fname: CString
|
dli_fname: cstring
|
||||||
dli_fbase: pointer
|
dli_fbase: pointer
|
||||||
dli_sname: CString
|
dli_sname: cstring
|
||||||
dli_saddr: pointer
|
dli_saddr: pointer
|
||||||
|
|
||||||
proc backtrace(symbols: ptr pointer, size: int): int {.
|
proc backtrace(symbols: ptr pointer, size: int): int {.
|
||||||
|
|
|
||||||
|
|
@ -472,17 +472,17 @@ proc Ze(a: int): int {.compilerproc.} =
|
||||||
proc Ze64(a: int64): int64 {.compilerproc.} =
|
proc Ze64(a: int64): int64 {.compilerproc.} =
|
||||||
result = a
|
result = a
|
||||||
|
|
||||||
proc toU8(a: int): int8 {.noStackFrame, compilerproc.} =
|
proc ToU8(a: int): int8 {.noStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
return `a`;
|
return `a`;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc toU16(a: int): int16 {.noStackFrame, compilerproc.} =
|
proc ToU16(a: int): int16 {.noStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
return `a`;
|
return `a`;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc toU32(a: int): int32 {.noStackFrame, compilerproc.} =
|
proc ToU32(a: int): int32 {.noStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
return `a`;
|
return `a`;
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ discard """
|
||||||
WARNING: false first asseertion from bar
|
WARNING: false first asseertion from bar
|
||||||
ERROR: false second assertion from bar
|
ERROR: false second assertion from bar
|
||||||
-1
|
-1
|
||||||
tests/run/tfailedassert.nim:27 false assertion from foo
|
tests/assert/tfailedassert.nim:27 false assertion from foo
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ type
|
||||||
TButtonClicked = proc(button: PButton) {.nimcall.}
|
TButtonClicked = proc(button: PButton) {.nimcall.}
|
||||||
|
|
||||||
proc newButton*(onClick: TButtonClicked) =
|
proc newButton*(onClick: TButtonClicked) =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
newButton(onClick = proc(b: PButton) =
|
newButton(onClick = proc(b: PButton) =
|
||||||
|
|
|
||||||
32
tests/iter/tanoniter1.nim
Normal file
32
tests/iter/tanoniter1.nim
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
discard """
|
||||||
|
output: '''1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
1
|
||||||
|
2'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc factory(a, b: int): iterator (): int =
|
||||||
|
iterator foo(): int =
|
||||||
|
var x = a
|
||||||
|
while x <= b:
|
||||||
|
yield x
|
||||||
|
inc x
|
||||||
|
return foo
|
||||||
|
|
||||||
|
proc factory2(a, b: int): iterator (): int =
|
||||||
|
return iterator (): int =
|
||||||
|
var x = a
|
||||||
|
while x <= b:
|
||||||
|
yield x
|
||||||
|
inc x
|
||||||
|
|
||||||
|
let foo = factory 1, 4
|
||||||
|
|
||||||
|
for f in foo():
|
||||||
|
echo f
|
||||||
|
|
||||||
|
let foo2 = factory2 1,2
|
||||||
|
|
||||||
|
for f in foo2(): echo f
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''true'''
|
output: '''true'''
|
||||||
cmd: "nimrod cc --gc:none --hints:on $# $#"
|
cmd: "nimrod cc --gc:none --hints:on --warnings:off $# $#"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hashes
|
import hashes
|
||||||
|
|
|
||||||
7
tests/macros/tmemit.nim
Normal file
7
tests/macros/tmemit.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
discard """
|
||||||
|
out: '''HELLO WORLD'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros, strutils
|
||||||
|
|
||||||
|
emit("echo " & '"' & "hello world".toUpper & '"')
|
||||||
12
tests/parser/tcommand_as_expr.nim
Normal file
12
tests/parser/tcommand_as_expr.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: "12"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc foo(x: int): int = x-1
|
||||||
|
proc foo(x, y: int): int = x-y
|
||||||
|
|
||||||
|
let x = foo 7.foo, # comment here
|
||||||
|
foo(1, foo 8)
|
||||||
|
# 12 = 6 - -6
|
||||||
|
echo x
|
||||||
|
|
||||||
17
tests/parser/tdomulttest.nim
Normal file
17
tests/parser/tdomulttest.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
file: "tdomulttest.nim"
|
||||||
|
output: "555\ntest\nmulti lines\n99999999\nend"
|
||||||
|
disabled: true
|
||||||
|
"""
|
||||||
|
proc foo(bar, baz: proc (x: int): int) =
|
||||||
|
echo bar(555)
|
||||||
|
echo baz(99999999)
|
||||||
|
|
||||||
|
foo do (x: int) -> int:
|
||||||
|
return x
|
||||||
|
do (x: int) -> int:
|
||||||
|
echo("test")
|
||||||
|
echo("multi lines")
|
||||||
|
return x
|
||||||
|
|
||||||
|
echo("end")
|
||||||
15
tests/parser/tinvwhen.nim
Normal file
15
tests/parser/tinvwhen.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
discard """
|
||||||
|
file: "tinvwhen.nim"
|
||||||
|
line: 11
|
||||||
|
errormsg: "invalid indentation"
|
||||||
|
"""
|
||||||
|
# This was parsed even though it should not!
|
||||||
|
|
||||||
|
proc chdir(path: cstring): cint {.importc: "chdir", header: "dirHeader".}
|
||||||
|
|
||||||
|
proc getcwd(buf: cstring, buflen: cint): cstring
|
||||||
|
when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation
|
||||||
|
elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}
|
||||||
|
else: {.error: "os library not ported to your OS. Please help!".}
|
||||||
|
|
||||||
|
|
||||||
36
todo.txt
36
todo.txt
|
|
@ -1,18 +1,8 @@
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- test&finish first class iterators:
|
- better debugging support for writes to locations
|
||||||
* nested iterators
|
|
||||||
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
|
||||||
- document new templating symbol binding rules
|
- document new templating symbol binding rules
|
||||||
- make '--implicitStatic:on' the default
|
|
||||||
|
|
||||||
- special rule for ``[]=``
|
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``; general
|
|
||||||
lift mechanism in the compiler is already implemented for 'fields'
|
|
||||||
- built-in 'getImpl'
|
|
||||||
- optimize 'genericReset'; 'newException' leads to code bloat
|
|
||||||
- stack-less GC
|
|
||||||
- fix eval in macros.nim
|
- fix eval in macros.nim
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,8 +17,6 @@ Bugs
|
||||||
- docgen: sometimes effects are listed twice
|
- docgen: sometimes effects are listed twice
|
||||||
- 'result' is not properly cleaned for NRVO --> use uninit checking instead
|
- 'result' is not properly cleaned for NRVO --> use uninit checking instead
|
||||||
- sneaking with qualifiedLookup() is really broken!
|
- sneaking with qualifiedLookup() is really broken!
|
||||||
- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' --
|
|
||||||
use a qualifier
|
|
||||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||||
- osproc execProcesses can deadlock if all processes fail (as experienced
|
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||||
in c++ mode)
|
in c++ mode)
|
||||||
|
|
@ -37,12 +25,29 @@ Bugs
|
||||||
version 0.9.x
|
version 0.9.x
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- macros as type pragmas
|
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
||||||
|
- optimize 'genericReset'; 'newException' leads to code bloat
|
||||||
|
- stack-less GC
|
||||||
|
- implement strongSpaces:on
|
||||||
|
- make '--implicitStatic:on' the default
|
||||||
- implicit deref for parameter matching
|
- implicit deref for parameter matching
|
||||||
|
|
||||||
|
- special rule for ``[]=``
|
||||||
|
- ``=`` should be overloadable; requires specialization for ``=``; general
|
||||||
|
lift mechanism in the compiler is already implemented for 'fields'
|
||||||
|
- built-in 'getImpl'
|
||||||
|
|
||||||
|
- change comment handling in the AST; that's lots of work as c2nim and pas2nim
|
||||||
|
make use of the fast every node can have a comment!
|
||||||
|
|
||||||
|
|
||||||
|
version 0.9.X
|
||||||
|
=============
|
||||||
|
|
||||||
|
- macros as type pragmas
|
||||||
- lazy overloading resolution:
|
- lazy overloading resolution:
|
||||||
* special case ``tyStmt``
|
* special case ``tyStmt``
|
||||||
- FFI:
|
- FFI:
|
||||||
* test libffi on windows
|
|
||||||
* test: times.format with the FFI
|
* test: times.format with the FFI
|
||||||
- document NimMain and check whether it works for threading
|
- document NimMain and check whether it works for threading
|
||||||
- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
|
- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
|
||||||
|
|
@ -54,7 +59,6 @@ version 0.9.X
|
||||||
- implement the missing features wrt inheritance
|
- implement the missing features wrt inheritance
|
||||||
- better support for macros that rewrite procs
|
- better support for macros that rewrite procs
|
||||||
- macros need access to types and symbols (partially implemented)
|
- macros need access to types and symbols (partially implemented)
|
||||||
- perhaps: change comment handling in the AST
|
|
||||||
- enforce 'simpleExpr' more often --> doesn't work; tkProc is
|
- enforce 'simpleExpr' more often --> doesn't work; tkProc is
|
||||||
part of primary!
|
part of primary!
|
||||||
- the typeDesc/expr unification is weird and only necessary because of
|
- the typeDesc/expr unification is weird and only necessary because of
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,18 @@ proc exec(cmd: string) =
|
||||||
echo(cmd)
|
echo(cmd)
|
||||||
if os.execShellCmd(cmd) != 0: quit("external program failed")
|
if os.execShellCmd(cmd) != 0: quit("external program failed")
|
||||||
|
|
||||||
|
proc buildDocSamples(c: var TConfigData, destPath: string) =
|
||||||
|
## Special case documentation sample proc.
|
||||||
|
##
|
||||||
|
## The docgen sample needs to be generated twice with different commands, so
|
||||||
|
## it didn't make much sense to integrate into the existing generic
|
||||||
|
## documentation builders.
|
||||||
|
const src = "doc"/"docgen_sample.nim"
|
||||||
|
Exec("nimrod doc $# -o:$# $#" %
|
||||||
|
[c.nimrodArgs, destPath / "docgen_sample.html", src])
|
||||||
|
Exec("nimrod doc2 $# -o:$# $#" %
|
||||||
|
[c.nimrodArgs, destPath / "docgen_sample2.html", src])
|
||||||
|
|
||||||
proc buildDoc(c: var TConfigData, destPath: string) =
|
proc buildDoc(c: var TConfigData, destPath: string) =
|
||||||
# call nim for the documentation:
|
# call nim for the documentation:
|
||||||
for d in items(c.doc):
|
for d in items(c.doc):
|
||||||
|
|
@ -352,7 +364,9 @@ proc main(c: var TConfigData) =
|
||||||
copyDir("web/assets", "web/upload/assets")
|
copyDir("web/assets", "web/upload/assets")
|
||||||
buildNewsRss(c, "web/upload")
|
buildNewsRss(c, "web/upload")
|
||||||
buildAddDoc(c, "web/upload")
|
buildAddDoc(c, "web/upload")
|
||||||
|
buildDocSamples(c, "web/upload")
|
||||||
buildDoc(c, "web/upload")
|
buildDoc(c, "web/upload")
|
||||||
|
buildDocSamples(c, "doc")
|
||||||
buildDoc(c, "doc")
|
buildDoc(c, "doc")
|
||||||
buildPdfDoc(c, "doc")
|
buildPdfDoc(c, "doc")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ Changes affecting backwards compatibility
|
||||||
require an error code to be passed to them. This error code can be retrieved
|
require an error code to be passed to them. This error code can be retrieved
|
||||||
using the new ``OSLastError`` proc.
|
using the new ``OSLastError`` proc.
|
||||||
- ``os.parentDir`` now returns "" if there is no parent dir.
|
- ``os.parentDir`` now returns "" if there is no parent dir.
|
||||||
- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
|
- In CGI scripts stacktraces are shown to the user only
|
||||||
is used.
|
if ``cgi.setStackTraceStdout`` is used.
|
||||||
- The symbol binding rules for clean templates changed: ``bind`` for any
|
- The symbol binding rules for clean templates changed: ``bind`` for any
|
||||||
symbol that's not a parameter is now the default. ``mixin`` can be used
|
symbol that's not a parameter is now the default. ``mixin`` can be used
|
||||||
to require instantiation scope for a symbol.
|
to require instantiation scope for a symbol.
|
||||||
|
|
@ -71,8 +71,11 @@ Language Additions
|
||||||
- Added a new ``delegator pragma`` for handling calls to missing procs and
|
- Added a new ``delegator pragma`` for handling calls to missing procs and
|
||||||
fields at compile-time.
|
fields at compile-time.
|
||||||
- The overload resolution now supports ``static[T]`` params that must be
|
- The overload resolution now supports ``static[T]`` params that must be
|
||||||
evaluatable at compile-time.
|
evaluable at compile-time.
|
||||||
- Support for user-defined type classes has been added.
|
- Support for user-defined type classes has been added.
|
||||||
|
- The *command syntax* is supported in a lot more contexts.
|
||||||
|
- Anonymous iterators are now supported and iterators can capture variables
|
||||||
|
of an outer proc.
|
||||||
|
|
||||||
|
|
||||||
Tools improvements
|
Tools improvements
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson."""
|
||||||
|
|
||||||
[Documentation]
|
[Documentation]
|
||||||
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters;trmacros"
|
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters;trmacros"
|
||||||
doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools"
|
doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools;docgen"
|
||||||
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst;gc"
|
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst;gc"
|
||||||
srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
|
srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
|
||||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
|
srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue