merged upstream master
This commit is contained in:
commit
81a3585872
127 changed files with 4440 additions and 1496 deletions
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -172,6 +172,9 @@ type
|
|||
nkDiscardStmt, # a discard statement
|
||||
nkStmtList, # a list of statements
|
||||
nkImportStmt, # an import statement
|
||||
nkImportExceptStmt, # an import x except a statement
|
||||
nkExportStmt, # an export statement
|
||||
nkExportExceptStmt, # an 'export except' statement
|
||||
nkFromStmt, # a from * import statement
|
||||
nkIncludeStmt, # an include statement
|
||||
nkBindStmt, # a bind statement
|
||||
|
|
@ -647,7 +650,8 @@ type
|
|||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
# reference to another object to safe space)
|
||||
|
||||
constraint*: PNode # additional constraints like 'lit|result'
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TType* = object of TIdObj # types are identical iff they have the
|
||||
# same id; there may be multiple copies of a type
|
||||
|
|
@ -673,7 +677,6 @@ type
|
|||
align*: int # the type's alignment requirements
|
||||
containerID*: int # used for type checking of generics
|
||||
loc*: TLoc
|
||||
constraint*: PNode # additional constraints like 'lit|result'
|
||||
|
||||
TPair*{.final.} = object
|
||||
key*, val*: PObject
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
|||
[istr, makeYamlString($n.kind)])
|
||||
if maxRecDepth != 0:
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
|
||||
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
||||
appf(result, ",$N$1\"floatVal\": $2",
|
||||
|
|
@ -585,8 +585,9 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
|
|||
proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
|
||||
var h: THash = n.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == n:
|
||||
InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
if data[h] == n:
|
||||
# allowed for 'export' feature:
|
||||
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
|
|
@ -617,23 +618,23 @@ proc StrTableAdd(t: var TStrTable, n: PSym) =
|
|||
StrTableRawInsert(t.data, n)
|
||||
inc(t.counter)
|
||||
|
||||
proc StrTableIncl*(t: var TStrTable, n: PSym): bool =
|
||||
proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
# returns true if n is already in the string table:
|
||||
# It is essential that `n` is written nevertheless!
|
||||
# This way the newest redefinition is picked by the semantic analyses!
|
||||
assert n.name != nil
|
||||
var h: THash = n.name.h and high(t.data)
|
||||
while true:
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
if it.name.id == n.name.id:
|
||||
if it == nil: break
|
||||
if it.name.id == n.name.id:
|
||||
t.data[h] = n # overwrite it with newer definition!
|
||||
return true # found it
|
||||
h = nextTry(h, high(t.data))
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
StrTableEnlarge(t)
|
||||
StrTableRawInsert(t.data, n)
|
||||
else:
|
||||
else:
|
||||
assert(t.data[h] == nil)
|
||||
t.data[h] = n
|
||||
inc(t.counter)
|
||||
|
|
|
|||
90
compiler/babelcmd.nim
Normal file
90
compiler/babelcmd.nim
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Implements some helper procs for Babel (Nimrod's package manager) support.
|
||||
|
||||
import parseutils, strutils, strtabs, os, options, msgs, lists
|
||||
|
||||
proc addPath*(path: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, path):
|
||||
lists.PrependStr(options.searchPaths, path)
|
||||
|
||||
proc versionSplitPos(s: string): int =
|
||||
result = s.len-2
|
||||
while result > 1 and s[result] in {'0'..'9', '.'}: dec result
|
||||
if s[result] != '-': result = s.len
|
||||
|
||||
const
|
||||
latest = "head"
|
||||
|
||||
proc `<.`(a, b: string): bool =
|
||||
# wether a has a smaller version than b:
|
||||
if a == latest: return false
|
||||
var i = 0
|
||||
var j = 0
|
||||
var verA = 0
|
||||
var verB = 0
|
||||
while true:
|
||||
let ii = parseInt(a, verA, i)
|
||||
let jj = parseInt(b, verB, j)
|
||||
# if A has no number left, but B has, B is prefered: 0.8 vs 0.8.3
|
||||
if ii <= 0 or jj <= 0: return jj > 0
|
||||
if verA < verB: return true
|
||||
elif verA > verB: return false
|
||||
# else: same version number; continue:
|
||||
inc i, ii
|
||||
inc j, jj
|
||||
if a[i] == '.': inc i
|
||||
if b[j] == '.': inc j
|
||||
|
||||
proc addPackage(packages: PStringTable, p: string) =
|
||||
let x = versionSplitPos(p)
|
||||
let name = p.subStr(0, x-1)
|
||||
if x < p.len:
|
||||
let version = p.subStr(x+1)
|
||||
if packages[name] <. version:
|
||||
packages[name] = version
|
||||
else:
|
||||
packages[name] = latest
|
||||
|
||||
iterator chosen(packages: PStringTable): string =
|
||||
for key, val in pairs(packages):
|
||||
let res = if val == latest: key else: key & '-' & val
|
||||
yield res
|
||||
|
||||
proc addBabelPath(p: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, p):
|
||||
Message(info, hintPath, p)
|
||||
lists.PrependStr(options.lazyPaths, p)
|
||||
|
||||
proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
||||
proc hasNimFile(dir: string): bool =
|
||||
for kind, path in walkDir(dir):
|
||||
if kind == pcFile and path.endsWith(".nim"):
|
||||
result = true
|
||||
break
|
||||
if hasNimFile(p):
|
||||
addBabelPath(p, info)
|
||||
else:
|
||||
for kind, p2 in walkDir(p):
|
||||
if hasNimFile(p2): addBabelPath(p2, info)
|
||||
|
||||
proc addPathRec(dir: string, info: TLineInfo) =
|
||||
var packages = newStringTable(modeStyleInsensitive)
|
||||
var pos = dir.len-1
|
||||
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
||||
for k,p in os.walkDir(dir):
|
||||
if k == pcDir and p[pos] != '.':
|
||||
addPackage(packages, p)
|
||||
for p in packages.chosen:
|
||||
addPathWithNimFiles(p, info)
|
||||
|
||||
proc babelPath*(path: string, info: TLineInfo) =
|
||||
addPathRec(path, info)
|
||||
addBabelPath(path, info)
|
||||
|
|
@ -42,6 +42,7 @@ proc parseDefine(p: var TParser): PNode =
|
|||
result = newNodeP(nkTemplateDef, p)
|
||||
getTok(p)
|
||||
addSon(result, skipIdentExport(p))
|
||||
addSon(result, ast.emptyNode)
|
||||
eat(p, pxParLe)
|
||||
var params = newNodeP(nkFormalParams, p)
|
||||
# return type; not known yet:
|
||||
|
|
@ -60,6 +61,7 @@ proc parseDefine(p: var TParser): PNode =
|
|||
addSon(result, ast.emptyNode) # no generic parameters
|
||||
addSon(result, params)
|
||||
addSon(result, ast.emptyNode) # no pragmas
|
||||
addSon(result, ast.emptyNode)
|
||||
var kind = parseDefineBody(p, result)
|
||||
params.sons[0] = newIdentNodeP(kind, p)
|
||||
eatNewLine(p, result)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ int aw_instance_callback_set (AW_CALLBACK c, callback_t callback);
|
|||
|
||||
unsigned long int wawa;
|
||||
|
||||
#define MAX(x, y) ((x) < (y)? (y) : (x))
|
||||
|
||||
#define AW_BUILD 85 // AW 5.0
|
||||
// Limits
|
||||
#define AW_MAX_AVCHANGE_PER_SECOND 10
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
proc addComma(r: PRope): PRope =
|
||||
result = if r == nil: r else: con(r, ~", ")
|
||||
|
||||
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2);$n"
|
||||
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri.sons[0], op)
|
||||
var pl: PRope
|
||||
|
|
@ -164,7 +164,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
if i < length - 1: app(pl, ~", ")
|
||||
|
||||
template genCallPattern =
|
||||
lineF(p, cpsStmts, CallPattern, op.r, pl, pl.addComma, rawProc)
|
||||
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||
|
||||
let rawProc = getRawProcType(p, typ)
|
||||
if typ.sons[0] != nil:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -939,22 +939,31 @@ proc genNew(p: BProc, e: PNode) =
|
|||
var
|
||||
a, b: TLoc
|
||||
reftype, bt: PType
|
||||
sizeExpr: PRope
|
||||
refType = skipTypes(e.sons[1].typ, abstractVarRange)
|
||||
InitLocExpr(p, e.sons[1], a)
|
||||
initLoc(b, locExpr, a.t, OnHeap)
|
||||
# 'genNew' also handles 'unsafeNew':
|
||||
if e.len == 3:
|
||||
var se: TLoc
|
||||
InitLocExpr(p, e.sons[2], se)
|
||||
sizeExpr = se.rdLoc
|
||||
else:
|
||||
sizeExpr = ropef("sizeof($1)",
|
||||
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
|
||||
let args = [getTypeDesc(p.module, reftype),
|
||||
genTypeInfo(p.module, refType),
|
||||
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))]
|
||||
sizeExpr]
|
||||
if a.s == OnHeap and optRefcGc in gGlobalOptions:
|
||||
# use newObjRC1 as an optimization; and we don't need 'keepAlive' either
|
||||
if canFormAcycle(a.t):
|
||||
linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc)
|
||||
b.r = ropecg(p.module, "($1) #newObjRC1($2, sizeof($3))", args)
|
||||
b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", args)
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
|
||||
else:
|
||||
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", args)
|
||||
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
||||
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
|
||||
bt = skipTypes(refType.sons[0], abstractRange)
|
||||
genObjectInit(p, cpsStmts, bt, a, false)
|
||||
|
|
@ -1645,7 +1654,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
initLocExpr(p, n.sons[0], a)
|
||||
var r = rdLoc(a)
|
||||
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and
|
||||
n.sons[0].kind notin {nkHiddenAddr, nkAddr}:
|
||||
n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}:
|
||||
app(r, "->Sup")
|
||||
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
||||
r = con("&", r)
|
||||
|
|
|
|||
|
|
@ -148,20 +148,47 @@ proc atEndMark(buf: cstring, pos: int): bool =
|
|||
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
|
||||
result = s == NimMergeEndMark.len
|
||||
|
||||
when false:
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
result = newMutableRope(30_000)
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR:
|
||||
pos = lexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of LF:
|
||||
pos = lexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of '\0':
|
||||
InternalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||
break
|
||||
else:
|
||||
if atEndMark(buf, pos):
|
||||
inc pos, NimMergeEndMark.len
|
||||
break
|
||||
result.data.add(buf[pos])
|
||||
inc pos
|
||||
L.bufpos = pos
|
||||
freezeMutableRope(result)
|
||||
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
result = newMutableRope(30_000)
|
||||
var r = newStringOfCap(30_000)
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR:
|
||||
pos = lexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
r.add(tnl)
|
||||
of LF:
|
||||
pos = lexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
r.add(tnl)
|
||||
of '\0':
|
||||
InternalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||
break
|
||||
|
|
@ -169,10 +196,10 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
|
|||
if atEndMark(buf, pos):
|
||||
inc pos, NimMergeEndMark.len
|
||||
break
|
||||
result.data.add(buf[pos])
|
||||
r.add(buf[pos])
|
||||
inc pos
|
||||
L.bufpos = pos
|
||||
freezeMutableRope(result)
|
||||
result = r.toRope
|
||||
|
||||
proc readKey(L: var TBaseLexer, result: var string) =
|
||||
var pos = L.bufpos
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ proc genBreakState(p: BProc, n: PNode) =
|
|||
lineF(p, cpsStmts, "if ((((NI*) $1.ClEnv)[0]) < 0) break;$n", [rdLoc(a)])
|
||||
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
|
||||
|
||||
proc genVarPrototypeAux(m: BModule, sym: PSym)
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
|
|
@ -140,6 +141,9 @@ proc genSingleVar(p: BProc, a: PNode) =
|
|||
genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
|
||||
# Alternative construction using default constructor (which may zeromem):
|
||||
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
||||
if sfExportc in v.flags and generatedHeader != nil:
|
||||
genVarPrototypeAux(generatedHeader, v)
|
||||
|
||||
else:
|
||||
assignLocalVar(p, v)
|
||||
initLocalVar(p, v, immediateAsgn)
|
||||
|
|
@ -878,7 +882,8 @@ proc genStmts(p: BProc, t: PNode) =
|
|||
# we have to emit the type information for object types here to support
|
||||
# separate compilation:
|
||||
genTypeSection(p.module, t)
|
||||
of nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
|
||||
of nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
nil
|
||||
of nkPragma: genPragma(p, t)
|
||||
|
|
|
|||
|
|
@ -558,17 +558,6 @@ include "ccgexprs.nim", "ccgstmts.nim"
|
|||
# ----------------------------- dynamic library handling -----------------
|
||||
# We don't finalize dynamic libs as this does the OS for us.
|
||||
|
||||
proc libCandidates(s: string, dest: var TStringSeq) =
|
||||
var le = strutils.find(s, '(')
|
||||
var ri = strutils.find(s, ')', le+1)
|
||||
if le >= 0 and ri > le:
|
||||
var prefix = substr(s, 0, le - 1)
|
||||
var suffix = substr(s, ri + 1)
|
||||
for middle in split(substr(s, le + 1, ri - 1), '|'):
|
||||
libCandidates(prefix & middle & suffix, dest)
|
||||
else:
|
||||
add(dest, s)
|
||||
|
||||
proc isGetProcAddr(lib: PLib): bool =
|
||||
let n = lib.path
|
||||
result = n.kind in nkCallKinds and n.typ != nil and
|
||||
|
|
@ -870,8 +859,6 @@ proc genVarPrototypeAux(m: BModule, sym: PSym) =
|
|||
|
||||
proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
genVarPrototypeAux(m, sym)
|
||||
if sfExportc in sym.flags and generatedHeader != nil:
|
||||
genVarPrototypeAux(generatedHeader, sym)
|
||||
|
||||
proc addIntTypes(result: var PRope) {.inline.} =
|
||||
appf(result, "#define NIM_INTBITS $1", [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -65,10 +65,10 @@ proc sameMethodBucket(a, b: PSym): bool =
|
|||
break
|
||||
if sameType(aa, bb) or
|
||||
(aa.kind == tyObject) and (bb.kind == tyObject) and
|
||||
(inheritanceDiff(bb, aa) < 0):
|
||||
(inheritanceDiff(bb, aa) < 0):
|
||||
nil
|
||||
else:
|
||||
return
|
||||
else:
|
||||
return
|
||||
result = true
|
||||
|
||||
proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
|
|
@ -106,17 +106,16 @@ proc methodDef*(s: PSym, fromCache: bool) =
|
|||
# attach to itself to prevent bugs:
|
||||
attachDispatcher(disp, newSymNode(disp))
|
||||
|
||||
proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
var t = methods[0].typ.sons[col]
|
||||
result = false
|
||||
if skipTypes(t, skipPtrs).kind == tyObject:
|
||||
for i in countup(1, high(methods)):
|
||||
if not SameType(methods[i].typ.sons[col], t):
|
||||
if skipTypes(t, skipPtrs).kind == tyObject:
|
||||
for i in countup(1, high(methods)):
|
||||
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
|
||||
if not SameType(t2, t):
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||
result = 0
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if Contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||
wordrecg, parseutils
|
||||
wordrecg, parseutils, babelcmd
|
||||
|
||||
proc writeCommandLineUsage*()
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
|
|||
|
||||
const
|
||||
HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2004-2012 by Andreas Rumpf\n"
|
||||
"Copyright (c) 2004-2013 by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
Usage = slurp"doc/basicopt.txt".replace("//", "")
|
||||
|
|
@ -194,20 +194,6 @@ proc processPath(path: string): string =
|
|||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
|
||||
proc addPath(path: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, path):
|
||||
lists.PrependStr(options.searchPaths, path)
|
||||
|
||||
proc addPathRec(dir: string, info: TLineInfo) =
|
||||
var pos = dir.len-1
|
||||
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
||||
for k,p in os.walkDir(dir):
|
||||
if k == pcDir and p[pos] != '.':
|
||||
addPathRec(p, info)
|
||||
if not contains(options.searchPaths, p):
|
||||
Message(info, hintPath, p)
|
||||
lists.PrependStr(options.searchPaths, p)
|
||||
|
||||
proc track(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
|
||||
|
|
@ -227,11 +213,16 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
|||
of "path", "p":
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg), info)
|
||||
of "recursivepath":
|
||||
of "babelpath":
|
||||
if pass in {passCmd2, passPP}:
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
babelpath(path, info)
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
var path = processPath(arg)
|
||||
addPathRec(path, info)
|
||||
addPath(path, info)
|
||||
let path = processPath(arg)
|
||||
lists.ExcludeStr(options.searchPaths, path)
|
||||
lists.ExcludeStr(options.lazyPaths, path)
|
||||
of "nimcache":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.nimcacheDir = processPath(arg)
|
||||
|
|
@ -474,6 +465,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
|||
of "stdout":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optStdout)
|
||||
of "listfullpaths":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
gListFullPaths = true
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||
else: InvalidCmdLineOption(pass, switch, info)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ proc InitDefines*() =
|
|||
DefineSymbol("niminheritable")
|
||||
DefineSymbol("nimmixin")
|
||||
DefineSymbol("nimeffects")
|
||||
DefineSymbol("nimbabel")
|
||||
|
||||
# add platform specific symbols:
|
||||
case targetCPU
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
|||
for i in countup(0, sonsLen(n) - 1):
|
||||
var imported = getModuleName(n.sons[i])
|
||||
addDependencyAux(g.module.name.s, imported)
|
||||
of nkFromStmt:
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
var imported = getModuleName(n.sons[0])
|
||||
addDependencyAux(g.module.name.s, imported)
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
|
|
|
|||
|
|
@ -137,7 +137,27 @@ proc genRecComment(d: PDoc, n: PNode): PRope =
|
|||
if result != nil: return
|
||||
else:
|
||||
n.comment = nil
|
||||
|
||||
|
||||
proc findDocComment(n: PNode): PNode =
|
||||
if n == nil: return nil
|
||||
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
|
||||
for i in countup(0, safeLen(n)-1):
|
||||
result = findDocComment(n.sons[i])
|
||||
if result != nil: return
|
||||
|
||||
proc extractDocComment*(s: PSym, d: PDoc = nil): string =
|
||||
let n = findDocComment(s.ast)
|
||||
result = ""
|
||||
if not n.isNil:
|
||||
if not d.isNil:
|
||||
var dummyHasToc: bool
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||
toLineNumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options + {roSkipPounds}),
|
||||
result)
|
||||
else:
|
||||
result = n.comment.substr(2).replace("\n##", "\n").strip
|
||||
|
||||
proc isVisible(n: PNode): bool =
|
||||
result = false
|
||||
if n.kind == nkPostfix:
|
||||
|
|
@ -145,6 +165,9 @@ proc isVisible(n: PNode): bool =
|
|||
var v = n.sons[0].ident
|
||||
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
||||
elif n.kind == nkSym:
|
||||
# we cannot generate code for forwarded symbols here as we have no
|
||||
# exception tracking information here. Instead we copy over the comment
|
||||
# from the proc header.
|
||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(n.sons[0])
|
||||
|
|
@ -273,7 +296,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
|||
generateDoc(d, lastSon(n.sons[0]))
|
||||
of nkImportStmt:
|
||||
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
|
||||
of nkFromStmt: traceDeps(d, n.sons[0])
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
else: nil
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
|
|
@ -350,9 +373,11 @@ proc CommandRstAux(filename, outExt: string) =
|
|||
var d = newDocumentor(filen, options.gConfigVars)
|
||||
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
|
||||
{roSupportRawDirective})
|
||||
d.modDesc = newMutableRope(30_000)
|
||||
renderRstToOut(d[], rst, d.modDesc.data)
|
||||
freezeMutableRope(d.modDesc)
|
||||
var modDesc = newStringOfCap(30_000)
|
||||
#d.modDesc = newMutableRope(30_000)
|
||||
renderRstToOut(d[], rst, modDesc)
|
||||
#freezeMutableRope(d.modDesc)
|
||||
d.modDesc = toRope(modDesc)
|
||||
writeOutput(d, filename, outExt)
|
||||
generateIndex(d)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -207,27 +207,42 @@ proc genObjectInfo(p: var TProc, typ: PType, name: PRope) =
|
|||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
|
||||
proc genEnumInfo(p: var TProc, typ: PType, name: PRope) =
|
||||
var
|
||||
s, n: PRope
|
||||
length: int
|
||||
field: PSym
|
||||
length = sonsLen(typ.n)
|
||||
s = nil
|
||||
proc genTupleFields(p: var TProc, typ: PType): PRope =
|
||||
var s: PRope = nil
|
||||
for i in 0 .. <typ.len:
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
s.appf("{kind: 1, offset: \"Field$1\", len: 0, " &
|
||||
"typ: $2, name: \"Field$1\", sons: null}",
|
||||
[i.toRope, genTypeInfo(p, typ.sons[i])])
|
||||
result = ropef("{kind: 2, len: $1, offset: 0, " &
|
||||
"typ: null, name: null, sons: [$2]}", [toRope(typ.len), s])
|
||||
|
||||
proc genTupleInfo(p: var TProc, typ: PType, name: PRope) =
|
||||
var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n", [name, toRope(ord(typ.kind))])
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[toRope(typ.id), genTupleFields(p, typ)])
|
||||
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
|
||||
|
||||
proc genEnumInfo(p: var TProc, typ: PType, name: PRope) =
|
||||
let length = sonsLen(typ.n)
|
||||
var s: PRope = nil
|
||||
for i in countup(0, length - 1):
|
||||
if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
|
||||
field = typ.n.sons[i].sym
|
||||
let field = typ.n.sons[i].sym
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
|
||||
appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
|
||||
[toRope(field.position), name, makeCString(field.name.s)])
|
||||
n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
|
||||
[toRope(field.position), name, makeCString(extName)])
|
||||
var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
|
||||
"name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s])
|
||||
s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n", [name, toRope(ord(typ.kind))])
|
||||
prepend(p.g.typeInfo, s)
|
||||
app(p.g.typeInfo, n)
|
||||
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
|
||||
if typ.sons[0] != nil:
|
||||
if typ.sons[0] != nil:
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
|
||||
|
|
@ -259,7 +274,8 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope =
|
|||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.sons[1])])
|
||||
of tyEnum: genEnumInfo(p, t, result)
|
||||
of tyObject, tyTuple: genObjectInfo(p, t, result)
|
||||
of tyObject: genObjectInfo(p, t, result)
|
||||
of tyTuple: genTupleInfo(p, t, result)
|
||||
else: InternalError("genTypeInfo(" & $t.kind & ')')
|
||||
|
||||
proc gen(p: var TProc, n: PNode, r: var TCompRes)
|
||||
|
|
@ -938,7 +954,9 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
of skProc, skConverter, skMethod:
|
||||
discard mangleName(s)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s) or
|
||||
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||
nil
|
||||
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
|
||||
# we cannot produce code for the dispatcher yet:
|
||||
nil
|
||||
|
|
@ -962,24 +980,45 @@ proc genDeref(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
if a.kind != etyBaseIndex: InternalError(n.info, "genDeref")
|
||||
r.res = ropef("$1[$2]", [a.com, a.res])
|
||||
|
||||
proc genArg(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
gen(p, n, a)
|
||||
if a.kind == etyBaseIndex:
|
||||
app(r.res, a.com)
|
||||
app(r.res, ", ")
|
||||
app(r.res, a.res)
|
||||
else:
|
||||
app(r.res, mergeExpr(a))
|
||||
|
||||
proc genArgs(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
app(r.res, "(")
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i > 1: app(r.res, ", ")
|
||||
var a: TCompRes
|
||||
gen(p, n.sons[i], a)
|
||||
if a.kind == etyBaseIndex:
|
||||
app(r.res, a.com)
|
||||
app(r.res, ", ")
|
||||
app(r.res, a.res)
|
||||
else:
|
||||
app(r.res, mergeExpr(a))
|
||||
genArg(p, n.sons[i], r)
|
||||
app(r.res, ")")
|
||||
|
||||
proc genCall(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[0], r)
|
||||
genArgs(p, n, r)
|
||||
|
||||
proc genInfixCall(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[1], r)
|
||||
if r.kind == etyBaseIndex:
|
||||
if r.com == nil:
|
||||
GlobalError(n.info, "cannot invoke with infix syntax")
|
||||
r.res = ropef("$1[0]", [r.res, r.com])
|
||||
r.com = nil
|
||||
app(r.res, ".")
|
||||
var op: TCompRes
|
||||
gen(p, n.sons[0], op)
|
||||
app(r.res, mergeExpr(op))
|
||||
|
||||
app(r.res, "(")
|
||||
for i in countup(2, sonsLen(n) - 1):
|
||||
if i > 2: app(r.res, ", ")
|
||||
genArg(p, n.sons[i], r)
|
||||
app(r.res, ")")
|
||||
|
||||
proc genEcho(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "rawEcho")
|
||||
app(r.res, "rawEcho")
|
||||
|
|
@ -1176,10 +1215,13 @@ proc genConStrStr(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
proc genRepr(p: var TProc, n: PNode, r: var TCompRes) =
|
||||
var t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
case t.kind
|
||||
of tyInt..tyInt64:
|
||||
unaryExpr(p, n, r, "", "reprInt($1)")
|
||||
of tyInt..tyUInt64:
|
||||
unaryExpr(p, n, r, "", "(\"\"+ ($1))")
|
||||
of tyEnum, tyOrdinal:
|
||||
binaryExpr(p, n, r, "", "reprEnum($1, $2)")
|
||||
gen(p, n.sons[1], r)
|
||||
useMagic(p, "cstrToNimstr")
|
||||
r.res = ropef("cstrToNimstr($1.node.sons[$2].name)",
|
||||
[genTypeInfo(p, t), r.res])
|
||||
else:
|
||||
# XXX:
|
||||
internalError(n.info, "genRepr: Not implemented")
|
||||
|
|
@ -1463,7 +1505,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
of nkAsmStmt: genAsmStmt(p, n, r)
|
||||
of nkTryStmt: genTryStmt(p, n, r)
|
||||
of nkRaiseStmt: genRaiseStmt(p, n, r)
|
||||
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, nkImportStmt,
|
||||
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
var s = n.sons[namePos].sym
|
||||
|
|
@ -1510,9 +1553,12 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
else: r.res = toRope(f.ToStrMaxPrecision)
|
||||
of nkBlockExpr: genBlock(p, n, r)
|
||||
of nkIfExpr: genIfExpr(p, n, r)
|
||||
of nkCallKinds:
|
||||
of nkCallKinds:
|
||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
||||
genMagic(p, n, r)
|
||||
elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
|
||||
n.len >= 2:
|
||||
genInfixCall(p, n, r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
of nkCurly: genSetConstr(p, n, r)
|
||||
|
|
@ -1526,6 +1572,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
|
|||
of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
|
||||
of nkObjDownConv: gen(p, n.sons[0], r)
|
||||
of nkObjUpConv: upConv(p, n, r)
|
||||
of nkCast: gen(p, n.sons[1], r)
|
||||
of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
|
||||
of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
|
||||
of nkChckRange: genRangeChck(p, n, r, "chckRange")
|
||||
|
|
@ -1555,7 +1602,7 @@ proc newModule(module: PSym): BModule =
|
|||
|
||||
proc genHeader(): PRope =
|
||||
result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n$n" & "$nvar Globals = this;$n" &
|
||||
"/* (c) 2013 Andreas Rumpf */$n$n" & "$nvar Globals = this;$n" &
|
||||
"var framePtr = null;$n" & "var excHandler = null;$n",
|
||||
[toRope(versionAsString)])
|
||||
|
||||
|
|
|
|||
443
compiler/evalffi.nim
Normal file
443
compiler/evalffi.nim
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This file implements the FFI part of the evaluator for Nimrod code.
|
||||
|
||||
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
|
||||
|
||||
when defined(windows):
|
||||
const libcDll = "msvcrt.dll"
|
||||
else:
|
||||
const libcDll = "libc.so(.6|.5|)"
|
||||
|
||||
type
|
||||
TDllCache = tables.TTable[string, TLibHandle]
|
||||
var
|
||||
gDllCache = initTable[string, TLibHandle]()
|
||||
gExeHandle = LoadLib()
|
||||
|
||||
proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
|
||||
result = cache[dll]
|
||||
if result.isNil:
|
||||
var libs: seq[string] = @[]
|
||||
libCandidates(dll, libs)
|
||||
for c in libs:
|
||||
result = LoadLib(c)
|
||||
if not result.isNil: break
|
||||
if result.isNil:
|
||||
GlobalError(info, "cannot load: " & dll)
|
||||
cache[dll] = result
|
||||
|
||||
const
|
||||
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
|
||||
|
||||
proc importcSymbol*(sym: PSym): PNode =
|
||||
let name = ropeToStr(sym.loc.r)
|
||||
|
||||
# the AST does not support untyped pointers directly, so we use an nkIntLit
|
||||
# that contains the address instead:
|
||||
result = newNodeIT(nkPtrLit, sym.info, sym.typ)
|
||||
case name
|
||||
of "stdin": result.intVal = cast[TAddress](system.stdin)
|
||||
of "stdout": result.intVal = cast[TAddress](system.stdout)
|
||||
of "stderr": result.intVal = cast[TAddress](system.stderr)
|
||||
else:
|
||||
let lib = sym.annex
|
||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
|
||||
var theAddr: pointer
|
||||
if lib.isNil and not gExehandle.isNil:
|
||||
# first try this exe itself:
|
||||
theAddr = gExehandle.symAddr(name)
|
||||
# then try libc:
|
||||
if theAddr.isNil:
|
||||
let dllhandle = gDllCache.getDll(libcDll, sym.info)
|
||||
theAddr = dllhandle.checkedSymAddr(name)
|
||||
else:
|
||||
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
|
||||
theAddr = dllhandle.checkedSymAddr(name)
|
||||
result.intVal = cast[TAddress](theAddr)
|
||||
|
||||
proc mapType(t: ast.PType): ptr libffi.TType =
|
||||
if t == nil: return addr libffi.type_void
|
||||
|
||||
case t.kind
|
||||
of tyBool, tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64, tySet:
|
||||
case t.getSize
|
||||
of 1: result = addr libffi.type_uint8
|
||||
of 2: result = addr libffi.type_sint16
|
||||
of 4: result = addr libffi.type_sint32
|
||||
of 8: result = addr libffi.type_sint64
|
||||
else: result = nil
|
||||
of tyFloat, tyFloat64: result = addr libffi.type_double
|
||||
of tyFloat32: result = addr libffi.type_float
|
||||
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
|
||||
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
|
||||
result = addr libffi.type_pointer
|
||||
of tyDistinct:
|
||||
result = mapType(t.sons[0])
|
||||
else:
|
||||
result = nil
|
||||
# too risky:
|
||||
#of tyFloat128: result = addr libffi.type_longdouble
|
||||
|
||||
proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
|
||||
case cc
|
||||
of ccDefault: result = DEFAULT_ABI
|
||||
of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
|
||||
of ccCDecl: result = DEFAULT_ABI
|
||||
else:
|
||||
GlobalError(info, "cannot map calling convention to FFI")
|
||||
|
||||
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
|
||||
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
|
||||
template `+!`(x, y: expr): expr {.immediate.} =
|
||||
cast[pointer](cast[TAddress](x) + y)
|
||||
|
||||
proc packSize(v: PNode, typ: PType): int =
|
||||
## computes the size of the blob
|
||||
case typ.kind
|
||||
of tyPtr, tyRef, tyVar:
|
||||
if v.kind in {nkNilLit, nkPtrLit}:
|
||||
result = sizeof(pointer)
|
||||
else:
|
||||
result = sizeof(pointer) + packSize(v.sons[0], typ.sons[0])
|
||||
of tyDistinct, tyGenericInst:
|
||||
result = packSize(v, typ.sons[0])
|
||||
of tyArray, tyArrayConstr:
|
||||
# consider: ptr array[0..1000_000, int] which is common for interfacing;
|
||||
# we use the real length here instead
|
||||
if v.kind in {nkNilLit, nkPtrLit}:
|
||||
result = sizeof(pointer)
|
||||
elif v.len != 0:
|
||||
result = v.len * packSize(v.sons[0], typ.sons[1])
|
||||
else:
|
||||
result = typ.getSize.int
|
||||
|
||||
proc pack(v: PNode, typ: PType, res: pointer)
|
||||
|
||||
proc getField(n: PNode; position: int): PSym =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = getField(n.sons[i], position)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
result = getField(n.sons[0], position)
|
||||
if result != nil: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = getField(lastSon(n.sons[i]), position)
|
||||
if result != nil: return
|
||||
else: internalError(n.info, "getField(record case branch)")
|
||||
of nkSym:
|
||||
if n.sym.position == position: result = n.sym
|
||||
else: nil
|
||||
|
||||
proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||
InternalAssert x.kind == nkPar
|
||||
# compute the field's offsets:
|
||||
discard typ.getSize
|
||||
for i in countup(0, sonsLen(x) - 1):
|
||||
var it = x.sons[i]
|
||||
if it.kind == nkExprColonExpr:
|
||||
internalAssert it.sons[0].kind == nkSym
|
||||
let field = it.sons[0].sym
|
||||
pack(it.sons[1], field.typ, res +! field.offset)
|
||||
elif typ.n != nil:
|
||||
let field = getField(typ.n, i)
|
||||
pack(it, field.typ, res +! field.offset)
|
||||
else:
|
||||
GlobalError(x.info, "cannot pack unnamed tuple")
|
||||
|
||||
const maxPackDepth = 20
|
||||
var packRecCheck = 0
|
||||
|
||||
proc pack(v: PNode, typ: PType, res: pointer) =
|
||||
template awr(T, v: expr) {.immediate, dirty.} =
|
||||
wr(T, res, v)
|
||||
|
||||
case typ.kind
|
||||
of tyBool: awr(bool, v.intVal != 0)
|
||||
of tyChar: awr(char, v.intVal.chr)
|
||||
of tyInt: awr(int, v.intVal.int)
|
||||
of tyInt8: awr(int8, v.intVal.int8)
|
||||
of tyInt16: awr(int16, v.intVal.int16)
|
||||
of tyInt32: awr(int32, v.intVal.int32)
|
||||
of tyInt64: awr(int64, v.intVal.int64)
|
||||
of tyUInt: awr(uint, v.intVal.uint)
|
||||
of tyUInt8: awr(uint8, v.intVal.uint8)
|
||||
of tyUInt16: awr(uint16, v.intVal.uint16)
|
||||
of tyUInt32: awr(uint32, v.intVal.uint32)
|
||||
of tyUInt64: awr(uint64, v.intVal.uint64)
|
||||
of tyEnum, tySet:
|
||||
case v.typ.getSize
|
||||
of 1: awr(uint8, v.intVal.uint8)
|
||||
of 2: awr(uint16, v.intVal.uint16)
|
||||
of 4: awr(int32, v.intVal.int32)
|
||||
of 8: awr(int64, v.intVal.int64)
|
||||
else:
|
||||
GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
|
||||
of tyFloat: awr(float, v.floatVal)
|
||||
of tyFloat32: awr(float32, v.floatVal)
|
||||
of tyFloat64: awr(float64, v.floatVal)
|
||||
|
||||
of tyPointer, tyProc, tyCString, tyString:
|
||||
if v.kind == nkNilLit:
|
||||
# nothing to do since the memory is 0 initialized anyway
|
||||
nil
|
||||
elif v.kind == nkPtrLit:
|
||||
awr(pointer, cast[pointer](v.intVal))
|
||||
elif v.kind in {nkStrLit..nkTripleStrLit}:
|
||||
awr(cstring, cstring(v.strVal))
|
||||
else:
|
||||
GlobalError(v.info, "cannot map pointer/proc value to FFI")
|
||||
of tyPtr, tyRef, tyVar:
|
||||
if v.kind == nkNilLit:
|
||||
# nothing to do since the memory is 0 initialized anyway
|
||||
nil
|
||||
elif v.kind == nkPtrLit:
|
||||
awr(pointer, cast[pointer](v.intVal))
|
||||
else:
|
||||
if packRecCheck > maxPackDepth:
|
||||
packRecCheck = 0
|
||||
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
inc packRecCheck
|
||||
pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
|
||||
dec packRecCheck
|
||||
awr(pointer, res +! sizeof(pointer))
|
||||
of tyArray, tyArrayConstr:
|
||||
let baseSize = typ.sons[1].getSize
|
||||
for i in 0 .. <v.len:
|
||||
pack(v.sons[i], typ.sons[1], res +! i * baseSize)
|
||||
of tyObject, tyTuple:
|
||||
packObject(v, typ, res)
|
||||
of tyNil:
|
||||
nil
|
||||
of tyDistinct, tyGenericInst:
|
||||
pack(v, typ.sons[0], res)
|
||||
else:
|
||||
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
|
||||
proc unpack(x: pointer, typ: PType, n: PNode): PNode
|
||||
|
||||
proc unpackObjectAdd(x: pointer, n, result: PNode) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
unpackObjectAdd(x, n.sons[i], result)
|
||||
of nkRecCase:
|
||||
GlobalError(result.info, "case objects cannot be unpacked")
|
||||
of nkSym:
|
||||
var pair = newNodeI(nkExprColonExpr, result.info, 2)
|
||||
pair.sons[0] = n
|
||||
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
|
||||
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
|
||||
result.add pair
|
||||
else: nil
|
||||
|
||||
proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
|
||||
# compute the field's offsets:
|
||||
discard typ.getSize
|
||||
|
||||
# iterate over any actual field of 'n' ... if n is nil we need to create
|
||||
# the nkPar node:
|
||||
if n.isNil:
|
||||
result = newNode(nkPar)
|
||||
result.typ = typ
|
||||
if typ.n.isNil:
|
||||
InternalError("cannot unpack unnamed tuple")
|
||||
unpackObjectAdd(x, typ.n, result)
|
||||
else:
|
||||
result = n
|
||||
if result.kind != nkPar:
|
||||
GlobalError(n.info, "cannot map value from FFI")
|
||||
if typ.n.isNil:
|
||||
GlobalError(n.info, "cannot unpack unnamed tuple")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr:
|
||||
internalAssert it.sons[0].kind == nkSym
|
||||
let field = it.sons[0].sym
|
||||
it.sons[1] = unpack(x +! field.offset, field.typ, it.sons[1])
|
||||
else:
|
||||
let field = getField(typ.n, i)
|
||||
n.sons[i] = unpack(x +! field.offset, field.typ, it)
|
||||
|
||||
proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
|
||||
if n.isNil:
|
||||
result = newNode(nkBracket)
|
||||
result.typ = typ
|
||||
newSeq(result.sons, lengthOrd(typ).int)
|
||||
else:
|
||||
result = n
|
||||
if result.kind != nkBracket:
|
||||
GlobalError(n.info, "cannot map value from FFI")
|
||||
let baseSize = typ.sons[1].getSize
|
||||
for i in 0 .. < result.len:
|
||||
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
|
||||
|
||||
proc canonNodeKind(k: TNodeKind): TNodeKind =
|
||||
case k
|
||||
of nkCharLit..nkUInt64Lit: result = nkIntLit
|
||||
of nkFloatLit..nkFloat128Lit: result = nkFloatLit
|
||||
of nkStrLit..nkTripleStrLit: result = nkStrLit
|
||||
else: result = k
|
||||
|
||||
proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
template aw(k, v, field: expr) {.immediate, dirty.} =
|
||||
if n.isNil:
|
||||
result = newNode(k)
|
||||
result.typ = typ
|
||||
else:
|
||||
# check we have the right field:
|
||||
result = n
|
||||
if result.kind.canonNodeKind != k.canonNodeKind:
|
||||
#echo "expected ", k, " but got ", result.kind
|
||||
#debug result
|
||||
return newNodeI(nkExceptBranch, n.info)
|
||||
#GlobalError(n.info, "cannot map value from FFI")
|
||||
result.field = v
|
||||
|
||||
template setNil() =
|
||||
if n.isNil:
|
||||
result = newNode(nkNilLit)
|
||||
result.typ = typ
|
||||
else:
|
||||
reset n[]
|
||||
result = n
|
||||
result.kind = nkNilLit
|
||||
result.typ = typ
|
||||
|
||||
template awi(kind, v: expr) {.immediate, dirty.} = aw(kind, v, intVal)
|
||||
template awf(kind, v: expr) {.immediate, dirty.} = aw(kind, v, floatVal)
|
||||
template aws(kind, v: expr) {.immediate, dirty.} = aw(kind, v, strVal)
|
||||
|
||||
case typ.kind
|
||||
of tyBool: awi(nkIntLit, rd(bool, x).ord)
|
||||
of tyChar: awi(nkCharLit, rd(char, x).ord)
|
||||
of tyInt: awi(nkIntLit, rd(int, x))
|
||||
of tyInt8: awi(nkInt8Lit, rd(int8, x))
|
||||
of tyInt16: awi(nkInt16Lit, rd(int16, x))
|
||||
of tyInt32: awi(nkInt32Lit, rd(int32, x))
|
||||
of tyInt64: awi(nkInt64Lit, rd(int64, x))
|
||||
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
|
||||
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
|
||||
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
|
||||
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
|
||||
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
|
||||
of tyEnum:
|
||||
case typ.getSize
|
||||
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
|
||||
of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
|
||||
of 4: awi(nkIntLit, rd(int32, x).biggestInt)
|
||||
of 8: awi(nkIntLit, rd(int64, x).biggestInt)
|
||||
else:
|
||||
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
of tyFloat: awf(nkFloatLit, rd(float, x))
|
||||
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
|
||||
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
|
||||
of tyPointer, tyProc:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n != nil and n.kind == nkStrLit:
|
||||
# we passed a string literal as a pointer; however strings are already
|
||||
# in their unboxed representation so nothing it to be unpacked:
|
||||
result = n
|
||||
else:
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
of tyPtr, tyRef, tyVar:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n == nil or n.kind == nkPtrLit:
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
elif n != nil and n.len == 1:
|
||||
internalAssert n.kind == nkRefTy
|
||||
n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
|
||||
result = n
|
||||
else:
|
||||
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
of tyObject, tyTuple:
|
||||
result = unpackObject(x, typ, n)
|
||||
of tyArray, tyArrayConstr:
|
||||
result = unpackArray(x, typ, n)
|
||||
of tyCString, tyString:
|
||||
let p = rd(cstring, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
else:
|
||||
aws(nkStrLit, $p)
|
||||
of tyNil:
|
||||
setNil()
|
||||
of tyDistinct, tyGenericInst:
|
||||
result = unpack(x, typ.sons[0], n)
|
||||
else:
|
||||
# XXX what to do with 'array' here?
|
||||
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
|
||||
proc fficast*(x: PNode, destTyp: PType): PNode =
|
||||
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer,
|
||||
tyProc, tyCString, tyString,
|
||||
tySequence}:
|
||||
result = newNodeIT(x.kind, x.info, destTyp)
|
||||
result.intVal = x.intVal
|
||||
elif x.kind == nkNilLit:
|
||||
result = newNodeIT(x.kind, x.info, destTyp)
|
||||
else:
|
||||
# we play safe here and allocate the max possible size:
|
||||
let size = max(packSize(x, x.typ), packSize(x, destTyp))
|
||||
var a = alloc0(size)
|
||||
pack(x, x.typ, a)
|
||||
# cast through a pointer needs a new inner object:
|
||||
let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
|
||||
else: x.copyTree
|
||||
y.typ = x.typ
|
||||
result = unpack(a, destTyp, y)
|
||||
dealloc a
|
||||
|
||||
proc callForeignFunction*(call: PNode): PNode =
|
||||
InternalAssert call.sons[0].kind == nkPtrLit
|
||||
|
||||
var cif: TCif
|
||||
var sig: TParamList
|
||||
# use the arguments' types for varargs support:
|
||||
for i in 1..call.len-1:
|
||||
sig[i-1] = mapType(call.sons[i].typ)
|
||||
if sig[i-1].isNil:
|
||||
GlobalError(call.info, "cannot map FFI type")
|
||||
|
||||
let typ = call.sons[0].typ
|
||||
if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
|
||||
mapType(typ.sons[0]), sig) != OK:
|
||||
GlobalError(call.info, "error in FFI call")
|
||||
|
||||
var args: TArgList
|
||||
let fn = cast[pointer](call.sons[0].intVal)
|
||||
for i in 1 .. call.len-1:
|
||||
var t = call.sons[i].typ
|
||||
args[i-1] = alloc0(packSize(call.sons[i], t))
|
||||
pack(call.sons[i], t, args[i-1])
|
||||
let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
|
||||
else: alloc(typ.sons[0].getSize.int)
|
||||
|
||||
libffi.call(cif, fn, retVal, args)
|
||||
|
||||
if retVal.isNil:
|
||||
result = emptyNode
|
||||
else:
|
||||
result = unpack(retVal, typ.sons[0], nil)
|
||||
result.info = call.info
|
||||
|
||||
if retVal != nil: dealloc retVal
|
||||
for i in 1 .. call.len-1:
|
||||
call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
|
||||
dealloc args[i-1]
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -18,6 +18,9 @@ import
|
|||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||
parser, ropes, rodread, idgen, osproc, streams, evaltempl
|
||||
|
||||
when hasFFI:
|
||||
import evalffi
|
||||
|
||||
type
|
||||
PStackFrame* = ref TStackFrame
|
||||
TStackFrame*{.final.} = object
|
||||
|
|
@ -34,12 +37,20 @@ type
|
|||
## emConst?)
|
||||
emStatic ## evaluate for enforced compile time eval
|
||||
## ('static' context)
|
||||
|
||||
TSandboxFlag* = enum ## what the evaluation engine should allow
|
||||
allowCast, ## allow unsafe language feature: 'cast'
|
||||
allowFFI, ## allow the FFI
|
||||
allowInfiniteLoops ## allow endless loops
|
||||
TSandboxFlags* = set[TSandboxFlag]
|
||||
|
||||
TEvalContext* = object of passes.TPassContext
|
||||
module*: PSym
|
||||
tos*: PStackFrame # top of stack
|
||||
lastException*: PNode
|
||||
callsite: PNode # for 'callsite' magic
|
||||
mode*: TEvalMode
|
||||
features: TSandboxFlags
|
||||
globals*: TIdNodeTable # state of global vars
|
||||
getType*: proc(n: PNode): PNode {.closure.}
|
||||
|
||||
|
|
@ -65,6 +76,7 @@ proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
|
|||
new(result)
|
||||
result.module = module
|
||||
result.mode = mode
|
||||
result.features = {allowFFI}
|
||||
initIdNodeTable(result.globals)
|
||||
|
||||
proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} =
|
||||
|
|
@ -78,7 +90,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} =
|
|||
proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
|
||||
|
||||
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
|
||||
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
|
||||
result = newNodeI(nkExceptBranch, info)
|
||||
# creating a nkExceptBranch without sons
|
||||
# means that it could not be evaluated
|
||||
|
|
@ -162,9 +174,12 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
|
|||
of nkExceptBranch, nkReturnToken: break
|
||||
else: nil
|
||||
dec(gWhileCounter)
|
||||
if gWhileCounter <= 0:
|
||||
stackTrace(c, n, errTooManyIterations)
|
||||
break
|
||||
if gWhileCounter <= 0:
|
||||
if allowInfiniteLoops in c.features:
|
||||
gWhileCounter = 0
|
||||
else:
|
||||
stackTrace(c, n, errTooManyIterations)
|
||||
break
|
||||
|
||||
proc evalBlock(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
|
|
@ -303,9 +318,54 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
|
|||
else:
|
||||
if x.kind notin {nkEmpty..nkNilLit}:
|
||||
discardSons(x)
|
||||
for i in countup(0, sonsLen(result) - 1): addSon(x, result.sons[i])
|
||||
for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
|
||||
result = emptyNode
|
||||
|
||||
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
|
||||
result = efLValue in flags or n.typ == nil or
|
||||
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
|
||||
|
||||
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
||||
# We need to return a node to the actual value,
|
||||
# which can be modified.
|
||||
var x = c
|
||||
while x != nil:
|
||||
if sym.kind == skResult and x.params.len > 0:
|
||||
result = x.params[0]
|
||||
if result == nil: result = emptyNode
|
||||
return
|
||||
result = IdNodeTableGet(x.mapping, sym)
|
||||
if result != nil and not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
if result != nil: return
|
||||
x = x.next
|
||||
#internalError(sym.info, "cannot eval " & sym.name.s)
|
||||
result = raiseCannotEval(nil, sym.info)
|
||||
#result = emptyNode
|
||||
|
||||
proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||
if sfCompileTime in s.flags or c.mode == emRepl:
|
||||
result = IdNodeTableGet(c.globals, s)
|
||||
if result != nil:
|
||||
if not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
else:
|
||||
when hasFFI:
|
||||
if sfImportc in s.flags and allowFFI in c.features:
|
||||
result = importcSymbol(s)
|
||||
IdNodeTablePut(c.globals, s, result)
|
||||
return result
|
||||
|
||||
result = s.ast
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
result = getNullValue(s.typ, s.info)
|
||||
else:
|
||||
result = evalAux(c, result, {})
|
||||
if isSpecial(result): return
|
||||
IdNodeTablePut(c.globals, s, result)
|
||||
else:
|
||||
result = raiseCannotEval(nil, s.info)
|
||||
|
||||
proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||
var d = newStackFrame()
|
||||
d.call = n
|
||||
|
|
@ -336,51 +396,21 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
|||
if isSpecial(result): return
|
||||
d.params[i] = result
|
||||
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
|
||||
|
||||
when hasFFI:
|
||||
if sfImportc in prc.sym.flags and allowFFI in c.features:
|
||||
var newCall = newNodeI(nkCall, n.info, n.len)
|
||||
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
||||
for i in 1 .. <n.len:
|
||||
newCall.sons[i] = d.params[i]
|
||||
return callForeignFunction(newCall)
|
||||
|
||||
pushStackFrame(c, d)
|
||||
result = evalAux(c, prc.sym.getBody, {})
|
||||
if result.kind == nkExceptBranch: return
|
||||
if n.typ != nil: result = d.params[0]
|
||||
popStackFrame(c)
|
||||
|
||||
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
|
||||
result = efLValue in flags or n.typ == nil or
|
||||
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
|
||||
|
||||
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
||||
# We need to return a node to the actual value,
|
||||
# which can be modified.
|
||||
var x = c
|
||||
while x != nil:
|
||||
if sym.kind == skResult and x.params.len > 0:
|
||||
result = x.params[0]
|
||||
if result == nil: result = emptyNode
|
||||
return
|
||||
result = IdNodeTableGet(x.mapping, sym)
|
||||
if result != nil and not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
if result != nil: return
|
||||
x = x.next
|
||||
#internalError(sym.info, "cannot eval " & sym.name.s)
|
||||
result = raiseCannotEval(nil, sym.info)
|
||||
#result = emptyNode
|
||||
|
||||
proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||
if sfCompileTime in s.flags or c.mode == emRepl:
|
||||
result = IdNodeTableGet(c.globals, s)
|
||||
if result != nil:
|
||||
if not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
else:
|
||||
result = s.ast
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
result = getNullValue(s.typ, s.info)
|
||||
else:
|
||||
result = evalAux(c, result, {})
|
||||
if isSpecial(result): return
|
||||
IdNodeTablePut(c.globals, s, result)
|
||||
else:
|
||||
result = raiseCannotEval(nil, s.info)
|
||||
|
||||
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = evalAux(c, n.sons[0], flags)
|
||||
if isSpecial(result): return
|
||||
|
|
@ -519,7 +549,9 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
|||
of skConst: result = s.ast
|
||||
of skEnumField: result = newIntNodeT(s.position, n)
|
||||
else: result = nil
|
||||
if result == nil or {sfImportc, sfForward} * s.flags != {}:
|
||||
let mask = if hasFFI and allowFFI in c.features: {sfForward}
|
||||
else: {sfImportc, sfForward}
|
||||
if result == nil or mask * s.flags != {}:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
|
||||
|
|
@ -617,6 +649,18 @@ proc evalConv(c: PEvalContext, n: PNode): PNode =
|
|||
# foldConv() cannot deal with everything that we want to do here:
|
||||
result = a
|
||||
|
||||
proc evalCast(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
if allowCast in c.features:
|
||||
when hasFFI:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
InternalAssert result.typ != nil
|
||||
result = fficast(result, n.typ)
|
||||
else:
|
||||
result = evalConv(c, n)
|
||||
else:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
proc evalCheckedFieldAccess(c: PEvalContext, n: PNode,
|
||||
flags: TEvalFlags): PNode =
|
||||
result = evalAux(c, n.sons[0], flags)
|
||||
|
|
@ -1363,7 +1407,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
|||
result.typ = n.typ
|
||||
of nkPragmaBlock:
|
||||
result = evalAux(c, n.sons[1], flags)
|
||||
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||
of nkCast:
|
||||
result = evalCast(c, n, flags)
|
||||
of nkIdentDefs, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||
nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt, nkBindStmt:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
of nkRefTy:
|
||||
|
|
@ -1388,7 +1434,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
|||
if sonsLen(result) >= 1:
|
||||
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
|
||||
else:
|
||||
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n))
|
||||
stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
|
||||
|
||||
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||
var p = newEvalContext(module, mode)
|
||||
|
|
@ -1431,8 +1477,9 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
|||
dec(evalTemplateCounter)
|
||||
c.callsite = nil
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var c = newEvalContext(module, emRepl)
|
||||
c.features = {allowCast, allowFFI, allowInfiniteLoops}
|
||||
pushStackFrame(c, newStackFrame())
|
||||
result = c
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@
|
|||
|
||||
import
|
||||
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
|
||||
semdata, passes
|
||||
semdata, passes, renderer
|
||||
|
||||
proc evalImport*(c: PContext, n: PNode): PNode
|
||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym)
|
||||
|
||||
proc getModuleName*(n: PNode): string =
|
||||
# This returns a short relative module name without the nim extension
|
||||
|
|
@ -29,8 +28,11 @@ proc getModuleName*(n: PNode): string =
|
|||
of nkSym:
|
||||
result = n.sym.name.s
|
||||
else:
|
||||
internalError(n.info, "getModuleName")
|
||||
result = ""
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||
#localError(n.info, errGenerated,
|
||||
# "invalide module name: '$1'" % renderTree(n))
|
||||
#result = ""
|
||||
|
||||
proc checkModuleName*(n: PNode): int32 =
|
||||
# This returns the full canonical path for a given module import
|
||||
|
|
@ -42,42 +44,43 @@ proc checkModuleName*(n: PNode): int32 =
|
|||
else:
|
||||
result = fullPath.fileInfoIdx
|
||||
|
||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
# This does not handle stubs, because otherwise loading on demand would be
|
||||
# pointless in practice. So importing stubs is fine here!
|
||||
var copy = s # do not copy symbols when importing!
|
||||
# check if we have already a symbol of the same name:
|
||||
var check = StrTableGet(c.tab.stack[importTablePos], s.name)
|
||||
if check != nil and check.id != copy.id:
|
||||
if s.kind notin OverloadableSyms:
|
||||
if check != nil and check.id != s.id:
|
||||
if s.kind notin OverloadableSyms:
|
||||
# s and check need to be qualified:
|
||||
Incl(c.AmbiguousSymbols, copy.id)
|
||||
Incl(c.AmbiguousSymbols, s.id)
|
||||
Incl(c.AmbiguousSymbols, check.id)
|
||||
StrTableAdd(c.tab.stack[importTablePos], copy)
|
||||
if s.kind == skType:
|
||||
# thanks to 'export' feature, it could be we import the same symbol from
|
||||
# multiple sources, so we need to call 'StrTableAdd' here:
|
||||
StrTableAdd(c.tab.stack[importTablePos], s)
|
||||
if s.kind == skType:
|
||||
var etyp = s.typ
|
||||
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
|
||||
for j in countup(0, sonsLen(etyp.n) - 1):
|
||||
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
|
||||
for j in countup(0, sonsLen(etyp.n) - 1):
|
||||
var e = etyp.n.sons[j].sym
|
||||
if (e.Kind != skEnumField):
|
||||
if e.Kind != skEnumField:
|
||||
InternalError(s.info, "rawImportSymbol")
|
||||
# BUGFIX: because of aliases for enums the symbol may already
|
||||
# have been put into the symbol table
|
||||
# BUGFIX: but only iff they are the same symbols!
|
||||
var it: TIdentIter
|
||||
check = InitIdentIter(it, c.tab.stack[importTablePos], e.name)
|
||||
while check != nil:
|
||||
if check.id == e.id:
|
||||
while check != nil:
|
||||
if check.id == e.id:
|
||||
e = nil
|
||||
break
|
||||
break
|
||||
check = NextIdentIter(it, c.tab.stack[importTablePos])
|
||||
if e != nil:
|
||||
if e != nil:
|
||||
rawImportSymbol(c, e)
|
||||
else:
|
||||
# rodgen assures that converters and patterns are no stubs
|
||||
if s.kind == skConverter: addConverter(c, s)
|
||||
if hasPattern(s): addPattern(c, s)
|
||||
|
||||
|
||||
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
let ident = lookups.considerAcc(n)
|
||||
let s = StrTableGet(fromMod.tab, ident)
|
||||
|
|
@ -98,20 +101,43 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
|||
rawImportSymbol(c, e)
|
||||
e = NextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
|
||||
proc importAllSymbols(c: PContext, fromMod: PSym) =
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||
var i: TTabIter
|
||||
var s = InitTabIter(i, fromMod.tab)
|
||||
while s != nil:
|
||||
if s.kind != skModule:
|
||||
if s.kind != skEnumField:
|
||||
if not (s.Kind in ExportableSymKinds):
|
||||
while s != nil:
|
||||
if s.kind != skModule:
|
||||
if s.kind != skEnumField:
|
||||
if s.Kind notin ExportableSymKinds:
|
||||
InternalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
rawImportSymbol(c, s) # this is correct!
|
||||
if exceptSet.empty or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
s = NextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
var exceptSet: TIntSet
|
||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
|
||||
if n.isNil: return
|
||||
case n.kind
|
||||
of nkExportStmt:
|
||||
for a in n:
|
||||
assert a.kind == nkSym
|
||||
let s = a.sym
|
||||
if s.kind == skModule:
|
||||
importAllSymbolsExcept(c, s, exceptSet)
|
||||
elif exceptSet.empty or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
of nkExportExceptStmt:
|
||||
localError(n.info, errGenerated, "'export except' not implemented")
|
||||
else:
|
||||
for i in 0 ..safeLen(n)-1:
|
||||
importForwarded(c, n.sons[i], exceptSet)
|
||||
|
||||
proc evalImport(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var emptySet: TIntSet
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var f = checkModuleName(n.sons[i])
|
||||
if f != InvalidFileIDX:
|
||||
|
|
@ -120,7 +146,8 @@ proc evalImport(c: PContext, n: PNode): PNode =
|
|||
Message(n.sons[i].info, warnDeprecated, m.name.s)
|
||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
importAllSymbols(c, m)
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
importForwarded(c, m.ast, emptySet)
|
||||
|
||||
proc evalFrom(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
|
|
@ -131,3 +158,18 @@ proc evalFrom(c: PContext, n: PNode): PNode =
|
|||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
for i in countup(1, sonsLen(n) - 1): importSymbol(c, n.sons[i], m)
|
||||
|
||||
proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2)
|
||||
var f = checkModuleName(n.sons[0])
|
||||
if f != InvalidFileIDX:
|
||||
var m = gImportModule(c.module, f)
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
var exceptSet = initIntSet()
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
let ident = lookups.considerAcc(n.sons[i])
|
||||
exceptSet.incl(ident.id)
|
||||
importAllSymbolsExcept(c, m, exceptSet)
|
||||
importForwarded(c, m.ast, exceptSet)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -257,6 +257,8 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
|||
# Currently captures are restricted to a single level of nesting:
|
||||
LocalError(info, errIllegalCaptureX, local.name.s)
|
||||
i.fn.typ.callConv = ccClosure
|
||||
#echo "captureVar ", i.fn.name.s, i.fn.id, " ", local.name.s, local.id
|
||||
|
||||
incl(i.fn.typ.flags, tfCapturesEnv)
|
||||
|
||||
# we need to remember which inner most closure belongs to this lambda:
|
||||
|
|
@ -286,9 +288,10 @@ proc interestingVar(s: PSym): bool {.inline.} =
|
|||
sfGlobal notin s.flags
|
||||
|
||||
proc semCaptureSym*(s, owner: PSym) =
|
||||
if interestingVar(s) and owner.id != s.owner.id:
|
||||
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
|
||||
if owner.typ != nil and not isGenericRoutine(owner):
|
||||
owner.typ.callConv = ccClosure
|
||||
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
|
||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||
# here
|
||||
|
||||
|
|
|
|||
|
|
@ -89,9 +89,25 @@ proc Remove*(list: var TLinkedList, entry: PListEntry) =
|
|||
list.head = entry.next
|
||||
if entry.next != nil: entry.next.prev = entry.prev
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
|
||||
|
||||
proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
|
||||
if entry == list.head: return
|
||||
if entry == list.tail: list.tail = entry.prev
|
||||
if entry.next != nil: entry.next.prev = entry.prev
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
entry.prev = nil
|
||||
entry.next = list.head
|
||||
list.head = entry
|
||||
|
||||
proc ExcludeStr*(list: var TLinkedList, data: string) =
|
||||
var it = list.head
|
||||
while it != nil:
|
||||
let nxt = it.next
|
||||
if PStrEntry(it).data == data: remove(list, it)
|
||||
it = nxt
|
||||
|
||||
proc Find*(list: TLinkedList, fn: TCompareProc, closure: Pointer): PListEntry =
|
||||
result = list.head
|
||||
while result != nil:
|
||||
while result != nil:
|
||||
if fn(result, closure): return
|
||||
result = result.next
|
||||
|
|
|
|||
|
|
@ -103,17 +103,24 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
|||
line[0] == ' ' or
|
||||
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
|
||||
|
||||
proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
var inTripleString = false
|
||||
proc countTriples(s: string): int =
|
||||
var i = 0
|
||||
while i < s.len:
|
||||
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
|
||||
inc result
|
||||
inc i, 2
|
||||
inc i
|
||||
|
||||
proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
s.s = ""
|
||||
s.rd = 0
|
||||
var line = newStringOfCap(120)
|
||||
var triples = 0
|
||||
while ReadLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
|
||||
add(s.s, line)
|
||||
add(s.s, "\n")
|
||||
if line.contains("\"\"\""):
|
||||
inTripleString = not inTripleString
|
||||
if not continueLine(line, inTripleString): break
|
||||
inc triples, countTriples(line)
|
||||
if not continueLine(line, (triples and 1) == 1): break
|
||||
inc(s.lineOffset)
|
||||
result = min(bufLen, len(s.s) - s.rd)
|
||||
if result > 0:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -302,7 +302,7 @@ when has_LLVM_Backend:
|
|||
compileProject()
|
||||
|
||||
proc CommandCompileToEcmaScript =
|
||||
incl(gGlobalOptions, optSafeCode)
|
||||
#incl(gGlobalOptions, optSafeCode)
|
||||
setTarget(osEcmaScript, cpuEcmaScript)
|
||||
#initDefines()
|
||||
DefineSymbol("nimrod") # 'nimrod' is always defined
|
||||
|
|
@ -316,6 +316,7 @@ proc InteractivePasses =
|
|||
#setTarget(osNimrodVM, cpuNimrodVM)
|
||||
initDefines()
|
||||
DefineSymbol("nimrodvm")
|
||||
when hasFFI: DefineSymbol("nimffi")
|
||||
registerPass(verbosePass)
|
||||
registerPass(semPass)
|
||||
registerPass(evalPass)
|
||||
|
|
@ -524,11 +525,11 @@ proc MainCommand =
|
|||
gCmd = cmdGenDepend
|
||||
wantMainModule()
|
||||
CommandGenDepend()
|
||||
of "dump":
|
||||
of "dump":
|
||||
gCmd = cmdDump
|
||||
condsyms.ListSymbols()
|
||||
for it in iterSearchPath(): MsgWriteln(it)
|
||||
of "check":
|
||||
for it in iterSearchPath(searchPaths): MsgWriteln(it)
|
||||
of "check":
|
||||
gCmd = cmdCheck
|
||||
wantMainModule()
|
||||
CommandCheck()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -132,7 +132,7 @@ const
|
|||
errNumberOutOfRange: "number $1 out of valid range",
|
||||
errNnotAllowedInCharacter: "\\n not allowed in character literal",
|
||||
errClosingBracketExpected: "closing ']' expected, but end of file reached",
|
||||
errMissingFinalQuote: "missing final \'",
|
||||
errMissingFinalQuote: "missing final \' for character literal",
|
||||
errIdentifierExpected: "identifier expected, but found \'$1\'",
|
||||
errNewlineExpected: "newline expected, but found \'$1\'",
|
||||
errInvalidModuleName: "invalid module name: '$1'",
|
||||
|
|
@ -575,7 +575,15 @@ template toFilename*(info: TLineInfo): string =
|
|||
|
||||
template toFullPath*(info: TLineInfo): string =
|
||||
info.fileIndex.toFullPath
|
||||
|
||||
|
||||
proc toMsgFilename*(info: TLineInfo): string =
|
||||
if info.fileIndex < 0: result = "???"
|
||||
else:
|
||||
if gListFullPaths:
|
||||
result = fileInfos[info.fileIndex].fullPath
|
||||
else:
|
||||
result = fileInfos[info.fileIndex].projPath
|
||||
|
||||
proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
||||
result = info.line
|
||||
|
||||
|
|
@ -666,7 +674,7 @@ proc writeContext(lastinfo: TLineInfo) =
|
|||
var info = lastInfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
if msgContext[i] != lastInfo and msgContext[i] != info:
|
||||
MsgWriteln(posContextFormat % [toFilename(msgContext[i]),
|
||||
MsgWriteln(posContextFormat % [toMsgFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col),
|
||||
getMessageStr(errInstantiationFrom, "")])
|
||||
|
|
@ -720,7 +728,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
|||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
frmt = posHintFormat
|
||||
inc(gHintCounter)
|
||||
let s = frmt % [toFilename(info), coordToStr(info.line),
|
||||
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col), getMessageStr(msg, arg)]
|
||||
if not ignoreMsg:
|
||||
MsgWriteln(s)
|
||||
|
|
@ -732,6 +740,9 @@ proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
|||
proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doRaise)
|
||||
|
||||
proc GlobalError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doRaise)
|
||||
|
||||
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -13,6 +13,7 @@ import
|
|||
const
|
||||
hasTinyCBackend* = defined(tinyc)
|
||||
useEffectSystem* = true
|
||||
hasFFI* = defined(useFFI)
|
||||
|
||||
type # please make sure we have under 32 options
|
||||
# (improves code efficiency a lot!)
|
||||
|
|
@ -91,7 +92,7 @@ var
|
|||
optPatterns}
|
||||
gGlobalOptions*: TGlobalOptions = {optRefcGC, optThreadAnalysis}
|
||||
gExitcode*: int8
|
||||
searchPaths*: TLinkedList
|
||||
searchPaths*, lazyPaths*: TLinkedList
|
||||
outFile*: string = ""
|
||||
headerFile*: string = ""
|
||||
gCmd*: TCommands = cmdNone # the command
|
||||
|
|
@ -100,7 +101,10 @@ var
|
|||
gWholeProject*: bool # for 'doc2': output any dependency
|
||||
gEvalExpr*: string # expression for idetools --eval
|
||||
gLastCmdTime*: float # when caas is enabled, we measure each command
|
||||
gListFullPaths*: bool
|
||||
|
||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||
|
||||
const
|
||||
genSubDir* = "nimcache"
|
||||
NimExt* = "nim"
|
||||
|
|
@ -199,27 +203,53 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
|||
result = joinPath(subdir, tail)
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
||||
iterator iterSearchPath*(): string =
|
||||
iterator iterSearchPath*(SearchPaths: TLinkedList): string =
|
||||
var it = PStrEntry(SearchPaths.head)
|
||||
while it != nil:
|
||||
while it != nil:
|
||||
yield it.data
|
||||
it = PStrEntry(it.Next)
|
||||
|
||||
proc rawFindFile(f: string): string =
|
||||
for it in iterSearchPath():
|
||||
for it in iterSearchPath(SearchPaths):
|
||||
result = JoinPath(it, f)
|
||||
if ExistsFile(result):
|
||||
if existsFile(result):
|
||||
return result.canonicalizePath
|
||||
result = ""
|
||||
|
||||
proc rawFindFile2(f: string): string =
|
||||
var it = PStrEntry(lazyPaths.head)
|
||||
while it != nil:
|
||||
result = JoinPath(it.data, f)
|
||||
if existsFile(result):
|
||||
bringToFront(lazyPaths, it)
|
||||
return result.canonicalizePath
|
||||
it = PStrEntry(it.Next)
|
||||
result = ""
|
||||
|
||||
proc FindFile*(f: string): string {.procvar.} =
|
||||
result = rawFindFile(f)
|
||||
if len(result) == 0: result = rawFindFile(toLower(f))
|
||||
result = f.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.rawFindFile2
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile2
|
||||
|
||||
proc findModule*(modulename: string): string {.inline.} =
|
||||
# returns path to module
|
||||
result = FindFile(AddFileExt(modulename, nimExt))
|
||||
|
||||
proc libCandidates*(s: string, dest: var seq[string]) =
|
||||
var le = strutils.find(s, '(')
|
||||
var ri = strutils.find(s, ')', le+1)
|
||||
if le >= 0 and ri > le:
|
||||
var prefix = substr(s, 0, le - 1)
|
||||
var suffix = substr(s, ri + 1)
|
||||
for middle in split(substr(s, le + 1, ri - 1), '|'):
|
||||
libCandidates(prefix & middle & suffix, dest)
|
||||
else:
|
||||
add(dest, s)
|
||||
|
||||
proc binaryStrSearch*(x: openarray[string], y: string): int =
|
||||
var a = 0
|
||||
var b = len(x) - 1
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
|
|||
add(code, chr(ord(op)))
|
||||
|
||||
proc whichAlias*(p: PSym): TAliasRequest =
|
||||
if p.typ.constraint != nil:
|
||||
result = TAliasRequest(p.typ.constraint.strVal[0].ord)
|
||||
if p.constraint != nil:
|
||||
result = TAliasRequest(p.constraint.strVal[0].ord)
|
||||
|
||||
proc compileConstraints(p: PNode, result: var TPatternCode) =
|
||||
case p.kind
|
||||
|
|
|
|||
|
|
@ -875,10 +875,10 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
skipComment(p, result)
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}):
|
||||
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, newProcNode(nkDo, body.info, body))
|
||||
while true:
|
||||
while true:
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
|
|
@ -903,30 +903,34 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkElse: break
|
||||
|
||||
proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode =
|
||||
var a: PNode
|
||||
|
||||
proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p) # skip `import` or `export`
|
||||
optInd(p, result)
|
||||
var a = parseExpr(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType in {tkComma, tkExcept}:
|
||||
if p.tok.tokType == tkExcept:
|
||||
result.kind = succ(kind)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
a = parseExpr(p)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
expectNl(p)
|
||||
|
||||
proc parseIncludeStmt(p: var TParser): PNode =
|
||||
result = newNodeP(nkIncludeStmt, p)
|
||||
getTok(p) # skip `import` or `include`
|
||||
optInd(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkEof, tkSad, tkDed:
|
||||
break
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseSymbol(p)
|
||||
of tkRStrLit:
|
||||
a = newStrNodeP(nkRStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
of tkStrLit:
|
||||
a = newStrNodeP(nkStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
of tkTripleStrLit:
|
||||
a = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
while p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
var a = parseExpr(p)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
|
|
@ -934,37 +938,16 @@ proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode =
|
|||
expectNl(p)
|
||||
|
||||
proc parseFromStmt(p: var TParser): PNode =
|
||||
var a: PNode
|
||||
result = newNodeP(nkFromStmt, p)
|
||||
getTok(p) # skip `from`
|
||||
optInd(p, result)
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseSymbol(p)
|
||||
of tkRStrLit:
|
||||
a = newStrNodeP(nkRStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
of tkStrLit:
|
||||
a = newStrNodeP(nkStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
of tkTripleStrLit:
|
||||
a = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
return
|
||||
var a = parseExpr(p)
|
||||
addSon(result, a) #optInd(p, a);
|
||||
eat(p, tkImport)
|
||||
optInd(p, result)
|
||||
while true:
|
||||
case p.tok.tokType #optInd(p, a);
|
||||
of tkEof, tkSad, tkDed:
|
||||
break
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseSymbol(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
while p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
a = parseExpr(p)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
|
|
@ -1279,14 +1262,7 @@ proc parseEnum(p: var TParser): PNode =
|
|||
result = newNodeP(nkEnumTy, p)
|
||||
a = nil
|
||||
getTok(p)
|
||||
if false and p.tok.tokType == tkOf:
|
||||
a = newNodeP(nkOfInherit, p)
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
addSon(a, parseTypeDesc(p))
|
||||
addSon(result, a)
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
addSon(result, ast.emptyNode)
|
||||
optInd(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
|
|
@ -1425,18 +1401,6 @@ proc parseDistinct(p: var TParser): PNode =
|
|||
optInd(p, result)
|
||||
addSon(result, parseTypeDesc(p))
|
||||
|
||||
proc parsePointerInTypeSection(p: var TParser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
if not isOperator(p.tok):
|
||||
case p.tok.tokType
|
||||
of tkObject: addSon(result, parseObject(p))
|
||||
of tkTuple: addSon(result, parseTuple(p, true))
|
||||
else:
|
||||
if isExprStart(p):
|
||||
addSon(result, parseTypeDesc(p))
|
||||
|
||||
proc parseTypeDef(p: var TParser): PNode =
|
||||
result = newNodeP(nkTypeDef, p)
|
||||
addSon(result, identWithPragma(p))
|
||||
|
|
@ -1445,15 +1409,6 @@ proc parseTypeDef(p: var TParser): PNode =
|
|||
if p.tok.tokType == tkEquals:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
#var a: PNode
|
||||
#case p.tok.tokType
|
||||
#of tkObject: a = parseObject(p)
|
||||
#of tkEnum: a = parseEnum(p)
|
||||
#of tkDistinct: a = parseDistinct(p)
|
||||
#of tkTuple: a = parseTuple(p, true)
|
||||
#of tkRef: a = parsePointerInTypeSection(p, nkRefTy)
|
||||
#of tkPtr: a = parsePointerInTypeSection(p, nkPtrTy)
|
||||
#else: a = parseTypeDesc(p)
|
||||
addSon(result, parseTypeDefAux(p))
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
|
|
@ -1511,11 +1466,12 @@ proc simpleStmt(p: var TParser): PNode =
|
|||
of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt)
|
||||
of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt)
|
||||
of tkCurlyDotLe: result = parseStmtPragma(p)
|
||||
of tkImport: result = parseImportOrIncludeStmt(p, nkImportStmt)
|
||||
of tkImport: result = parseImport(p, nkImportStmt)
|
||||
of tkExport: result = parseImport(p, nkExportStmt)
|
||||
of tkFrom: result = parseFromStmt(p)
|
||||
of tkInclude: result = parseImportOrIncludeStmt(p, nkIncludeStmt)
|
||||
of tkInclude: result = parseIncludeStmt(p)
|
||||
of tkComment: result = newCommentStmt(p)
|
||||
else:
|
||||
else:
|
||||
if isExprStart(p): result = parseExprStmt(p)
|
||||
else: result = ast.emptyNode
|
||||
if result.kind != nkEmpty: skipComment(p, result)
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ proc inSymChoice(sc, x: PNode): bool =
|
|||
|
||||
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||
# check param constraints first here as this is quite optimized:
|
||||
if p.typ.constraint != nil:
|
||||
result = matchNodeKinds(p.typ.constraint, n)
|
||||
if p.constraint != nil:
|
||||
result = matchNodeKinds(p.constraint, n)
|
||||
if not result: return
|
||||
if isNil(n.typ):
|
||||
result = p.typ.kind in {tyEmpty, tyStmt}
|
||||
|
|
@ -237,6 +237,15 @@ proc addToArgList(result, n: PNode) =
|
|||
else:
|
||||
for i in 0 .. <n.len: result.add(n.sons[i])
|
||||
|
||||
when false:
|
||||
proc procPatternMatches*(c: PContext, s: PSym, n: PNode): bool =
|
||||
## for AST-based overloading:
|
||||
var ctx: TPatternContext
|
||||
ctx.owner = s
|
||||
ctx.c = c
|
||||
ctx.formals = sonsLen(s.typ)-1
|
||||
result = matches(ctx, s.ast.sons[patternPos], n)
|
||||
|
||||
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
## returns a tree to semcheck if the rule triggered; nil otherwise
|
||||
var ctx: TPatternContext
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
|||
a = procA.sons[i].sym
|
||||
b = procB.sons[i].sym
|
||||
if (a.name.id != b.name.id) or
|
||||
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
|
||||
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
|
||||
if (a.ast != nil) and (b.ast != nil):
|
||||
if not ExprStructuralEquivalent(a.ast, b.ast): return
|
||||
result = true
|
||||
|
|
@ -44,7 +44,7 @@ proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym =
|
|||
if equalGenericParams(result.ast.sons[genericParamsPos],
|
||||
fn.ast.sons[genericParamsPos]):
|
||||
case equalParams(result.typ.n, fn.typ.n)
|
||||
of paramsEqual:
|
||||
of paramsEqual:
|
||||
return
|
||||
of paramsIncompatible:
|
||||
LocalError(fn.info, errNotOverloadable, fn.name.s)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -753,8 +753,7 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
|
|||
|
||||
proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
if isNil(n): return
|
||||
var
|
||||
L: int
|
||||
var
|
||||
a: TContext
|
||||
if n.comment != nil: pushCom(g, n)
|
||||
case n.kind # atoms:
|
||||
|
|
@ -1096,7 +1095,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
incl(a.flags, rfInConstExpr)
|
||||
gsection(g, n, a, tkConst, "const")
|
||||
of nkVarSection, nkLetSection:
|
||||
L = sonsLen(n)
|
||||
var L = sonsLen(n)
|
||||
if L == 0: return
|
||||
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
|
||||
else: putWithSpace(g, tkLet, "let")
|
||||
|
|
@ -1134,13 +1133,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
put(g, tkCurlyDotLe, "{.")
|
||||
gcomma(g, n, emptyContext)
|
||||
put(g, tkCurlyDotRi, ".}")
|
||||
of nkImportStmt:
|
||||
putWithSpace(g, tkImport, "import")
|
||||
of nkImportStmt, nkExportStmt:
|
||||
if n.kind == nkImportStmt:
|
||||
putWithSpace(g, tkImport, "import")
|
||||
else:
|
||||
putWithSpace(g, tkExport, "export")
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
gcommaAux(g, n, g.indent)
|
||||
dedent(g)
|
||||
putNL(g)
|
||||
of nkImportExceptStmt, nkExportExceptStmt:
|
||||
if n.kind == nkImportExceptStmt:
|
||||
putWithSpace(g, tkImport, "import")
|
||||
else:
|
||||
putWithSpace(g, tkExport, "export")
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkExcept, "except")
|
||||
gcommaAux(g, n, g.indent, 1)
|
||||
gcoms(g)
|
||||
putNL(g)
|
||||
of nkFromStmt:
|
||||
putWithSpace(g, tkFrom, "from")
|
||||
gsub(g, n.sons[0])
|
||||
|
|
|
|||
|
|
@ -330,9 +330,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
|||
if r.s[r.pos] == '@':
|
||||
inc(r.pos)
|
||||
result.containerID = decodeVInt(r.s, r.pos)
|
||||
if r.s[r.pos] == '`':
|
||||
inc(r.pos)
|
||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||
decodeLoc(r, result.loc, info)
|
||||
while r.s[r.pos] == '^':
|
||||
inc(r.pos)
|
||||
|
|
@ -423,6 +420,9 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
|||
result.offset = - 1
|
||||
decodeLoc(r, result.loc, result.info)
|
||||
result.annex = decodeLib(r, info)
|
||||
if r.s[r.pos] == '#':
|
||||
inc(r.pos)
|
||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||
if r.s[r.pos] == '(':
|
||||
if result.kind in routineKinds:
|
||||
result.ast = decodeNodeLazyBody(r, result.info, result)
|
||||
|
|
|
|||
|
|
@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
|||
if t.containerID != 0:
|
||||
add(result, '@')
|
||||
encodeVInt(t.containerID, result)
|
||||
if t.constraint != nil:
|
||||
add(result, '`')
|
||||
encodeNode(w, UnknownLineInfo(), t.constraint, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
|
|
@ -295,6 +292,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
encodeVInt(s.offset, result)
|
||||
encodeLoc(w, s.loc, result)
|
||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||
if s.constraint != nil:
|
||||
add(result, '#')
|
||||
encodeNode(w, UnknownLineInfo(), s.constraint, result)
|
||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -38,13 +38,15 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
|||
proc semStmt(c: PContext, n: PNode): PNode
|
||||
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
|
||||
proc addResultNode(c: PContext, n: PNode)
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
proc finishMethod(c: PContext, s: PSym)
|
||||
|
||||
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -15,8 +15,22 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
|||
if a.kind == skMethod and b.kind == skMethod:
|
||||
var aa = lastSon(a.ast)
|
||||
var bb = lastSon(b.ast)
|
||||
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
|
||||
result = true
|
||||
if aa.kind == nkSym and bb.kind == nkSym:
|
||||
if aa.sym == bb.sym:
|
||||
result = true
|
||||
else:
|
||||
nil
|
||||
# generics have no dispatcher yet, so we need to compare the method
|
||||
# names; however, the names are equal anyway because otherwise we
|
||||
# wouldn't even consider them to be overloaded. But even this does
|
||||
# not work reliably! See tmultim6 for an example:
|
||||
# method collide[T](a: TThing, b: TUnit[T]) is instantiated and not
|
||||
# method collide[T](a: TUnit[T], b: TThing)! This means we need to
|
||||
# *instantiate* every candidate! However, we don't keep more than 2-3
|
||||
# candidated around so we cannot implement that for now. So in order
|
||||
# to avoid subtle problems, the call remains ambiguous and needs to
|
||||
# be disambiguated by the programmer; this way the right generic is
|
||||
# instantiated.
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds): TCandidate =
|
||||
|
|
@ -84,6 +98,35 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||
args])
|
||||
|
||||
|
||||
proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
|
||||
if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
|
||||
isGenericRoutine(a.sons[0].sym):
|
||||
let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, a.info)
|
||||
a.sons[0].sym = finalCallee
|
||||
a.sons[0].typ = finalCallee.typ
|
||||
#a.typ = finalCallee.typ.sons[0]
|
||||
|
||||
proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
||||
assert n.kind in nkCallKinds
|
||||
if x.genericConverter:
|
||||
for i in 1 .. <n.len:
|
||||
instGenericConvertersArg(c, n.sons[i], x)
|
||||
|
||||
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, a, arg, nil)
|
||||
if m.genericConverter and result != nil:
|
||||
instGenericConvertersArg(c, result, m)
|
||||
|
||||
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, n.typ, n, nil)
|
||||
if m.genericConverter and result != nil:
|
||||
instGenericConvertersArg(c, result, m)
|
||||
|
||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
|
|
@ -101,6 +144,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
|||
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||
return
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||
result.typ = finalCallee.typ.sons[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -318,7 +318,7 @@ proc semIs(c: PContext, n: PNode): PNode =
|
|||
if not containsGenericType(t1): result = evalIsOp(n)
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
let flags = {efDetermineType}
|
||||
const flags = {efDetermineType}
|
||||
for i in countup(1, n.sonsLen- 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||
|
|
@ -589,11 +589,12 @@ proc semStaticExpr(c: PContext, n: PNode): PNode =
|
|||
|
||||
proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
if efWantIterator in flags:
|
||||
result = semOverloadedCall(c, n, nOrig, {skIterator})
|
||||
elif efInTypeOf in flags:
|
||||
if flags*{efInTypeOf, efWantIterator} != {}:
|
||||
# consider: 'for x in pReturningArray()' --> we don't want the restriction
|
||||
# to 'skIterator' anymore; skIterator is preferred in sigmatch already for
|
||||
# typeof support.
|
||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||
result = semOverloadedCall(c, n, nOrig,
|
||||
result = semOverloadedCall(c, n, nOrig,
|
||||
{skProc, skMethod, skConverter, skMacro, skTemplate, skIterator})
|
||||
else:
|
||||
result = semOverloadedCall(c, n, nOrig,
|
||||
|
|
@ -663,6 +664,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
result = nil
|
||||
else:
|
||||
result = m.call
|
||||
instGenericConvertersSons(c, result, m)
|
||||
# we assume that a procedure that calls something indirectly
|
||||
# has side-effects:
|
||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||
|
|
@ -1658,6 +1660,26 @@ proc fixImmediateParams(n: PNode): PNode =
|
|||
|
||||
result = n
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
var x = newNodeI(n.kind, n.info)
|
||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
||||
for i in 0.. <n.len:
|
||||
let a = n.sons[i]
|
||||
var o: TOverloadIter
|
||||
var s = initOverloadIter(o, c, a)
|
||||
if s == nil:
|
||||
localError(a.info, errGenerated, "invalid expr for 'export': " &
|
||||
renderTree(a))
|
||||
while s != nil:
|
||||
if s.kind in ExportableSymKinds+{skModule}:
|
||||
x.add(newSymNode(s, a.info))
|
||||
s = nextOverloadIter(o, c, a)
|
||||
if c.module.ast.isNil:
|
||||
c.module.ast = newNodeI(nkStmtList, n.info)
|
||||
assert c.module.ast.kind == nkStmtList
|
||||
c.module.ast.add x
|
||||
result = n
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = n
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
|
|
@ -1851,12 +1873,18 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkImportStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import")
|
||||
result = evalImport(c, n)
|
||||
of nkImportExceptStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import")
|
||||
result = evalImportExcept(c, n)
|
||||
of nkFromStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "from")
|
||||
result = evalFrom(c, n)
|
||||
of nkIncludeStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
|
||||
result = evalInclude(c, n)
|
||||
of nkExportStmt, nkExportExceptStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "export")
|
||||
result = semExport(c, n)
|
||||
of nkPragmaBlock:
|
||||
result = semPragmaBlock(c, n)
|
||||
of nkStaticStmt:
|
||||
|
|
|
|||
|
|
@ -89,9 +89,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
|||
# add it here, so that recursive generic procs are possible:
|
||||
addDecl(c, result)
|
||||
pushProcCon(c, result)
|
||||
if result.kind in {skProc, skMethod, skConverter, skMacro}:
|
||||
addResult(c, result.typ.sons[0], n.info, result.kind)
|
||||
addResultNode(c, n)
|
||||
maybeAddResult(c, result, n)
|
||||
var b = n.sons[bodyPos]
|
||||
var symMap: TIdTable
|
||||
InitIdTable symMap
|
||||
|
|
@ -163,6 +161,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
result.typ = newTypeS(tyProc, c)
|
||||
rawAddSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
if result.kind == skIterator: result.typ.flags.incl(tfIterator)
|
||||
var oldPrc = GenericCacheGet(fn, entry[])
|
||||
if oldPrc == nil:
|
||||
fn.procInstCache.safeAdd(entry)
|
||||
|
|
@ -182,6 +181,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
popOwner()
|
||||
c.friendModule = oldFriend
|
||||
dec(c.InstCounter)
|
||||
if result.kind == skMethod: finishMethod(c, result)
|
||||
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||
var cl: TReplTypeVars
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -146,8 +146,11 @@ proc catches(tracked: PEffects, e: PType) =
|
|||
dec L
|
||||
else:
|
||||
inc i
|
||||
setLen(tracked.exc.sons, L)
|
||||
|
||||
if not isNil(tracked.exc.sons):
|
||||
setLen(tracked.exc.sons, L)
|
||||
else:
|
||||
assert L == 0
|
||||
|
||||
proc catchesAll(tracked: PEffects) =
|
||||
if not isNil(tracked.exc.sons):
|
||||
setLen(tracked.exc.sons, tracked.bottom)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -172,11 +172,16 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
|||
changeType(result, typ)
|
||||
|
||||
proc findShadowedVar(c: PContext, v: PSym): PSym =
|
||||
for i in countdown(c.tab.tos - 2, 0):
|
||||
for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
|
||||
let shadowed = StrTableGet(c.tab.stack[i], v.name)
|
||||
if shadowed != nil and shadowed.kind in skLocalVars:
|
||||
return shadowed
|
||||
|
||||
proc identWithin(n: PNode, s: PIdent): bool =
|
||||
for i in 0 .. n.safeLen-1:
|
||||
if identWithin(n.sons[i], s): return true
|
||||
result = n.kind == nkSym and n.sym.name.id == s.id
|
||||
|
||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||
if isTopLevel(c):
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||
|
|
@ -239,7 +244,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
let shadowed = findShadowedVar(c, v)
|
||||
if shadowed != nil:
|
||||
shadowed.flags.incl(sfShadowed)
|
||||
Message(a.info, warnShadowIdent, v.name.s)
|
||||
# a shadowed variable is an error unless it appears on the right
|
||||
# side of the '=':
|
||||
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
||||
Message(a.info, warnShadowIdent, v.name.s)
|
||||
if def != nil and def.kind != nkEmpty:
|
||||
# this is only needed for the evaluation pass:
|
||||
v.ast = def
|
||||
|
|
@ -247,7 +255,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
if a.kind != nkVarTuple:
|
||||
v.typ = typ
|
||||
b = newNodeI(nkIdentDefs, a.info)
|
||||
if gCmd == cmdDoc:
|
||||
if importantComments():
|
||||
# keep documentation information:
|
||||
b.comment = a.comment
|
||||
addSon(b, newSymNode(v))
|
||||
|
|
@ -287,7 +295,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
|||
v.ast = def # no need to copy
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
var b = newNodeI(nkConstDef, a.info)
|
||||
if gCmd == cmdDoc: b.comment = a.comment
|
||||
if importantComments(): b.comment = a.comment
|
||||
addSon(b, newSymNode(v))
|
||||
addSon(b, ast.emptyNode) # no type description
|
||||
addSon(b, copyTree(def))
|
||||
|
|
@ -368,6 +376,15 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
|||
b.add(ast.emptyNode)
|
||||
stmts.add(b)
|
||||
|
||||
proc addForVarDecl(c: PContext, v: PSym) =
|
||||
if warnShadowIdent in gNotes:
|
||||
let shadowed = findShadowedVar(c, v)
|
||||
if shadowed != nil:
|
||||
# XXX should we do this here?
|
||||
#shadowed.flags.incl(sfShadowed)
|
||||
Message(v.info, warnShadowIdent, v.name.s)
|
||||
addDecl(c, v)
|
||||
|
||||
proc semForVars(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var length = sonsLen(n)
|
||||
|
|
@ -383,7 +400,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
|||
# for an example:
|
||||
v.typ = n.sons[length-2].typ
|
||||
n.sons[0] = newSymNode(v)
|
||||
if sfGenSym notin v.flags: addDecl(c, v)
|
||||
if sfGenSym notin v.flags: addForVarDecl(c, v)
|
||||
else:
|
||||
LocalError(n.info, errWrongNumberOfVariables)
|
||||
elif length-2 != sonsLen(iter):
|
||||
|
|
@ -394,7 +411,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
|||
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
||||
v.typ = iter.sons[i]
|
||||
n.sons[i] = newSymNode(v)
|
||||
if sfGenSym notin v.flags: addDecl(c, v)
|
||||
if sfGenSym notin v.flags: addForVarDecl(c, v)
|
||||
Inc(c.p.nestedLoopCounter)
|
||||
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||
Dec(c.p.nestedLoopCounter)
|
||||
|
|
@ -669,17 +686,18 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
|
||||
s.options = gOptions
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
if sfImportc in s.flags:
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
if sfImportc in s.flags:
|
||||
LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
|
||||
if efDetermineType notin flags:
|
||||
pushProcCon(c, s)
|
||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||
addResultNode(c, n)
|
||||
popProcCon(c)
|
||||
sideEffectsCheck(c, s)
|
||||
#if efDetermineType notin flags:
|
||||
# XXX not good enough; see tnamedparamanonproc.nim
|
||||
pushProcCon(c, s)
|
||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||
addResultNode(c, n)
|
||||
popProcCon(c)
|
||||
sideEffectsCheck(c, s)
|
||||
else:
|
||||
LocalError(n.info, errImplOfXexpected, s.name.s)
|
||||
closeScope(c.tab) # close scope for parameters
|
||||
|
|
@ -689,13 +707,16 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
proc activate(c: PContext, n: PNode) =
|
||||
# XXX: This proc is part of my plan for getting rid of
|
||||
# forward declarations. stay tuned.
|
||||
case n.kind
|
||||
of nkLambdaKinds:
|
||||
discard semLambda(c, n, {})
|
||||
of nkCallKinds:
|
||||
for i in 1 .. <n.len: activate(c, n[i])
|
||||
else:
|
||||
nil
|
||||
when false:
|
||||
# well for now it breaks code ... I added the test case in main.nim of the
|
||||
# compiler itself to break bootstrapping :P
|
||||
case n.kind
|
||||
of nkLambdaKinds:
|
||||
discard semLambda(c, n, {})
|
||||
of nkCallKinds:
|
||||
for i in 1 .. <n.len: activate(c, n[i])
|
||||
else:
|
||||
nil
|
||||
|
||||
proc instantiateDestructor*(c: PContext, typ: PType): bool
|
||||
|
||||
|
|
@ -713,6 +734,12 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
|||
useSym(t.sons[i].destructor),
|
||||
n.sons[paramsPos][1][0]]))
|
||||
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||
if s.typ.sons[0] != nil and
|
||||
(s.kind != skIterator or s.typ.callConv == ccClosure):
|
||||
addResult(c, s.typ.sons[0], n.info, s.kind)
|
||||
addResultNode(c, n)
|
||||
|
||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
validPragmas: TSpecialWords): PNode =
|
||||
result = semProcAnnotation(c, n)
|
||||
|
|
@ -780,6 +807,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
|
||||
if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
|
||||
n.sons[namePos].sym = proto
|
||||
if importantComments() and not isNil(proto.ast.comment):
|
||||
n.comment = proto.ast.comment
|
||||
proto.ast = n # needed for code generation
|
||||
popOwner()
|
||||
pushOwner(s)
|
||||
|
|
@ -792,17 +821,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
ParamsTypeCheck(c, s.typ)
|
||||
pushProcCon(c, s)
|
||||
if s.typ.sons[0] != nil and
|
||||
(kind != skIterator or s.typ.callConv == ccClosure):
|
||||
addResult(c, s.typ.sons[0], n.info, kind)
|
||||
addResultNode(c, n)
|
||||
maybeAddResult(c, s, n)
|
||||
if sfImportc notin s.flags:
|
||||
# no semantic checking for importc:
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||
# context as it may even be evaluated in 'system.compiles':
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||
#if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
|
||||
popProcCon(c)
|
||||
else:
|
||||
if s.typ.sons[0] != nil and kind != skIterator:
|
||||
|
|
@ -846,31 +871,30 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
|||
proc semProc(c: PContext, n: PNode): PNode =
|
||||
result = semProcAux(c, n, skProc, procPragmas)
|
||||
|
||||
proc hasObjParam(s: PSym): bool =
|
||||
var t = s.typ
|
||||
for col in countup(1, sonsLen(t)-1):
|
||||
if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
|
||||
return true
|
||||
|
||||
proc finishMethod(c: PContext, s: PSym) =
|
||||
if hasObjParam(s):
|
||||
methodDef(s, false)
|
||||
|
||||
proc semMethod(c: PContext, n: PNode): PNode =
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method")
|
||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||
|
||||
var s = result.sons[namePos].sym
|
||||
var t = s.typ
|
||||
var hasObjParam = false
|
||||
|
||||
for col in countup(1, sonsLen(t)-1):
|
||||
if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
|
||||
hasObjParam = true
|
||||
break
|
||||
|
||||
# XXX this not really correct way to do it: Perhaps it should be done after
|
||||
# generic instantiation. Well it's good enough for now:
|
||||
if hasObjParam:
|
||||
methodDef(s, false)
|
||||
else:
|
||||
LocalError(n.info, errXNeedsParamObjectType, "method")
|
||||
if not isGenericRoutine(s):
|
||||
if hasObjParam(s):
|
||||
methodDef(s, false)
|
||||
else:
|
||||
LocalError(n.info, errXNeedsParamObjectType, "method")
|
||||
|
||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
|
||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||
var s = result.sons[namePos].sym
|
||||
var t = s.typ
|
||||
|
|
@ -1075,7 +1099,8 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
|||
varTyp = varId.sym.typ
|
||||
info = varId.info
|
||||
|
||||
if varTyp != nil and instantiateDestructor(c, varTyp):
|
||||
if varTyp != nil and instantiateDestructor(c, varTyp) and
|
||||
sfGlobal notin varId.sym.flags:
|
||||
var tryStmt = newNodeI(nkTryStmt, info)
|
||||
|
||||
if j < totalVars - 1:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
|
|||
|
|
@ -635,6 +635,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
genericParams.addSon(newSymNode(s))
|
||||
result = typeClass
|
||||
|
||||
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||
if n.kind == nkCurlyExpr:
|
||||
result = semTypeNode(c, n.sons[0], nil)
|
||||
constraint = semNodeKindConstraints(n)
|
||||
else:
|
||||
result = semTypeNode(c, n, nil)
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType, kind: TSymKind): PType =
|
||||
var
|
||||
|
|
@ -660,13 +667,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
checkMinSonsLen(a, 3)
|
||||
var
|
||||
typ: PType = nil
|
||||
def: PNode = nil
|
||||
def: PNode = nil
|
||||
constraint: PNode = nil
|
||||
length = sonsLen(a)
|
||||
hasType = a.sons[length-2].kind != nkEmpty
|
||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||
|
||||
if hasType:
|
||||
typ = semTypeNode(c, a.sons[length-2], nil)
|
||||
typ = semParamType(c, a.sons[length-2], constraint)
|
||||
|
||||
if hasDefault:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
|
|
@ -689,6 +697,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
arg.name.s, arg.info).skipIntLit
|
||||
arg.typ = finalType
|
||||
arg.position = counter
|
||||
arg.constraint = constraint
|
||||
inc(counter)
|
||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||
if ContainsOrIncl(check, arg.name.id):
|
||||
|
|
@ -787,6 +796,12 @@ proc semTypeExpr(c: PContext, n: PNode): PType =
|
|||
else:
|
||||
LocalError(n.info, errTypeExpected, n.renderTree)
|
||||
|
||||
proc freshType(res, prev: PType): PType {.inline.} =
|
||||
if prev.isNil:
|
||||
result = copyType(res, res.owner, keepId=false)
|
||||
else:
|
||||
result = res
|
||||
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = nil
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
|
|
@ -825,6 +840,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
checkSonsLen(n, 3)
|
||||
result = semTypeNode(c, n.sons[1], prev)
|
||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfNotNil)
|
||||
else:
|
||||
LocalError(n.info, errGenerated, "invalid type")
|
||||
|
|
@ -832,11 +848,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = semTypeExpr(c, n)
|
||||
else:
|
||||
result = semTypeExpr(c, n)
|
||||
of nkCurlyExpr:
|
||||
result = semTypeNode(c, n.sons[0], nil)
|
||||
if result != nil:
|
||||
result = copyType(result, getCurrOwner(), true)
|
||||
result.constraint = semNodeKindConstraints(n)
|
||||
of nkWhenStmt:
|
||||
var whenResult = semWhen(c, n, false)
|
||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||
|
|
@ -919,6 +930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
of nkSharedTy:
|
||||
checkSonsLen(n, 1)
|
||||
result = semTypeNode(c, n.sons[0], prev)
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfShared)
|
||||
else:
|
||||
LocalError(n.info, errTypeExpected)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -12,18 +12,19 @@
|
|||
|
||||
import
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys, condsyms, idents, lexer, options
|
||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils,
|
||||
docgen
|
||||
|
||||
type
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
TCandidate* {.final.} = object
|
||||
exactMatches*: int
|
||||
exactMatches*: int # also misused to prefer iters over procs
|
||||
genericMatches: int # also misused to prefer constraints
|
||||
subtypeMatches: int
|
||||
intConvMatches: int # conversions to int are not as expensive
|
||||
convMatches: int
|
||||
genericMatches: int
|
||||
state*: TCandidateState
|
||||
callee*: PType # may not be nil!
|
||||
calleeSym*: PSym # may be nil
|
||||
|
|
@ -33,6 +34,8 @@ type
|
|||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||
# for example
|
||||
proxyMatch*: bool # to prevent instantiations
|
||||
genericConverter*: bool # true if a generic converter needs to
|
||||
# be instantiated
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
|
|
@ -57,6 +60,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
|||
c.callee = callee
|
||||
c.call = nil
|
||||
c.baseTypeMatch = false
|
||||
c.genericConverter = false
|
||||
c.inheritancePenalty = 0
|
||||
|
||||
proc initCandidate*(c: var TCandidate, callee: PType) =
|
||||
|
|
@ -571,17 +575,27 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
|||
for i in countup(0, len(c.converters) - 1):
|
||||
var src = c.converters[i].typ.sons[1]
|
||||
var dest = c.converters[i].typ.sons[0]
|
||||
if (typeRel(m, f, dest) == isEqual) and
|
||||
(typeRel(m, src, a) == isEqual):
|
||||
# for generic type converters we need to check 'src <- a' before
|
||||
# 'f <- dest' in order to not break the unification:
|
||||
# see tests/tgenericconverter:
|
||||
let srca = typeRel(m, src, a)
|
||||
if srca notin {isEqual, isGeneric}: continue
|
||||
|
||||
let destIsGeneric = containsGenericType(dest)
|
||||
if destIsGeneric:
|
||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||
let fdest = typeRel(m, f, dest)
|
||||
if fdest in {isEqual, isGeneric}:
|
||||
markUsed(arg, c.converters[i])
|
||||
var s = newSymNode(c.converters[i])
|
||||
s.typ = c.converters[i].typ
|
||||
s.info = arg.info
|
||||
result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0])
|
||||
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
|
||||
addSon(result, s)
|
||||
addSon(result, copyTree(arg))
|
||||
inc(m.convMatches)
|
||||
return
|
||||
m.genericConverter = srca == isGeneric or destIsGeneric
|
||||
return result
|
||||
|
||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg: PNode): PNode =
|
||||
|
|
@ -692,8 +706,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
|||
else:
|
||||
result = userConvMatch(c, m, base(f), a, arg)
|
||||
|
||||
proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg, argOrig: PNode): PNode =
|
||||
proc ParamTypesMatch*(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg, argOrig: PNode): PNode =
|
||||
if arg == nil or arg.kind notin nkSymChoices:
|
||||
result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
|
||||
else:
|
||||
|
|
@ -739,27 +753,21 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
|
|||
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best],
|
||||
argOrig)
|
||||
|
||||
proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, a, arg, nil)
|
||||
|
||||
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, n.typ, n, nil)
|
||||
|
||||
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, a, ast.emptyNode, nil) != nil
|
||||
|
||||
proc setSon(father: PNode, at: int, son: PNode) =
|
||||
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
||||
father.sons[at] = son
|
||||
|
||||
proc matchesAux*(c: PContext, n, nOrig: PNode,
|
||||
m: var TCandidate, marker: var TIntSet) =
|
||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m: var TCandidate, marker: var TIntSet) =
|
||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||
if not formal.constraint.isNil:
|
||||
if matchNodeKinds(formal.constraint, n):
|
||||
# better match over other routines with no such restriction:
|
||||
inc(m.genericMatches, 100)
|
||||
else:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
|
||||
var f = 1 # iterates over formal parameters
|
||||
var a = 1 # iterates over the actual given arguments
|
||||
m.state = csMatch # until proven otherwise
|
||||
|
|
@ -792,7 +800,8 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
|
|||
n.sons[a].sons[1], nOrig.sons[a].sons[1])
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
return
|
||||
checkConstraint(n.sons[a].sons[1])
|
||||
if m.baseTypeMatch:
|
||||
assert(container == nil)
|
||||
container = newNodeI(nkBracket, n.sons[a].info)
|
||||
|
|
@ -837,10 +846,10 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
|
|||
m.baseTypeMatch = false
|
||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if arg == nil:
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
assert(container == nil)
|
||||
container = newNodeI(nkBracket, n.sons[a].info)
|
||||
addSon(container, arg)
|
||||
|
|
@ -849,6 +858,7 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
|
|||
if f != formalLen - 1: container = nil
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
checkConstraint(n.sons[a])
|
||||
inc(a)
|
||||
inc(f)
|
||||
|
||||
|
|
@ -880,4 +890,13 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
|||
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
||||
inc(f)
|
||||
|
||||
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
let res = paramTypesMatch(c, m, f, a, ast.emptyNode, nil)
|
||||
#instantiateGenericConverters(c, res, m)
|
||||
# XXX this is used by patterns.nim too; I think it's better to not
|
||||
# instantiate generic converters for that
|
||||
result = res != nil
|
||||
|
||||
include suggest
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -39,6 +39,8 @@ proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
|
|||
result.add($ToLinenumber(li))
|
||||
result.add(sep)
|
||||
result.add($ToColumn(li))
|
||||
result.add(sep)
|
||||
result.add(s.extractDocComment.escape)
|
||||
|
||||
proc SymToStr(s: PSym, isLocal: bool, section: string): string =
|
||||
result = SymToStr(s, isLocal, section, s.info)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -150,7 +150,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
|||
newVar.owner = getCurrOwner(c)
|
||||
IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar))
|
||||
var defs = newTransNode(nkIdentDefs, it.info, 3)
|
||||
if gCmd == cmdDoc:
|
||||
if importantComments():
|
||||
# keep documentation information:
|
||||
pnode(defs).comment = it.comment
|
||||
defs[0] = newSymNode(newVar).PTransNode
|
||||
|
|
@ -665,7 +665,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
of nkIdentDefs, nkConstDef:
|
||||
result = transformSons(c, n)
|
||||
# XXX comment handling really sucks:
|
||||
if gCmd == cmdDoc:
|
||||
if importantComments():
|
||||
pnode(result).comment = n.comment
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -632,7 +632,8 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
|
|||
result = SameTypeAux(a, b, c)
|
||||
|
||||
proc equalParam(a, b: PSym): TParamsEquality =
|
||||
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}):
|
||||
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}) and
|
||||
ExprStructuralEquivalent(a.constraint, b.constraint):
|
||||
if a.ast == b.ast:
|
||||
result = paramsEqual
|
||||
elif a.ast != nil and b.ast != nil:
|
||||
|
|
@ -875,20 +876,24 @@ proc inheritanceDiff*(a, b: PType): int =
|
|||
# | returns: -x iff `a` is the x'th direct superclass of `b`
|
||||
# | returns: +x iff `a` is the x'th direct subclass of `b`
|
||||
# | returns: `maxint` iff `a` and `b` are not compatible at all
|
||||
assert a.kind == tyObject
|
||||
assert b.kind == tyObject
|
||||
var x = a
|
||||
result = 0
|
||||
while x != nil:
|
||||
x = skipTypes(x, skipPtrs)
|
||||
if sameObjectTypes(x, b): return
|
||||
x = x.sons[0]
|
||||
dec(result)
|
||||
var y = b
|
||||
result = 0
|
||||
while y != nil:
|
||||
y = skipTypes(y, skipPtrs)
|
||||
if sameObjectTypes(y, a): return
|
||||
y = y.sons[0]
|
||||
inc(result)
|
||||
result = high(int)
|
||||
|
||||
|
||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool
|
||||
proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
||||
result = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue