Merge branch 'master' of gh:/Araq/Nimrod into upstream

This commit is contained in:
Zahary Karadjov 2013-05-04 17:50:38 +03:00
commit 3f1e9b3a25
942 changed files with 13790 additions and 3241 deletions

3
.gitignore vendored Executable file → Normal file
View file

@ -16,6 +16,7 @@ compiler/c2nim/nimcache
compiler/pas2nim/nimcache
misc
doc/*.html
doc/*.pdf
doc/*.idx
/web/upload
koch
@ -28,6 +29,8 @@ examples/cross_todo/nimrod_backend/backend
examples/cross_todo/nimrod_backend/testbackend
examples/cross_todo/nimrod_backend/todo.sqlite3
examples/cross_todo/nimrod_commandline/nimtodo
install.sh
deinstall.sh
# iOS specific wildcards.
*.mode1v3

0
build.bat Executable file → Normal file
View file

49
compiler/ast.nim Executable file → Normal file
View file

@ -71,21 +71,25 @@ type
nkDotCall, # used to temporarily flag a nkCall node;
# this is used
# for transforming ``s.len`` to ``len(s)``
nkCommand, # a call like ``p 2, 4`` without parenthesis
nkCall, # a call like p(x, y) or an operation like +(a, b)
nkCallStrLit, # a call with a string literal
# x"abc" has two sons: nkIdent, nkRStrLit
# x"""abc""" has two sons: nkIdent, nkTripleStrLit
nkInfix, # a call like (a + b)
nkPrefix, # a call like !a
nkPostfix, # something like a! (also used for visibility)
nkHiddenCallConv, # an implicit type conversion via a type converter
nkExprEqExpr, # a named parameter with equals: ''expr = expr''
nkExprColonExpr, # a named parameter with colon: ''expr: expr''
nkIdentDefs, # a definition like `a, b: typeDesc = expr`
# either typeDesc or expr may be nil; used in
# formal parameters, var statements, etc.
nkVarTuple, # a ``var (a, b) = expr`` construct
nkInfix, # a call like (a + b)
nkPrefix, # a call like !a
nkPostfix, # something like a! (also used for visibility)
nkPar, # syntactic (); may be a tuple constructor
nkObjConstr, # object constructor: T(a: 1, b: 2)
nkCurly, # syntactic {}
nkCurlyExpr, # an expression like a{i}
nkBracket, # syntactic []
@ -109,7 +113,6 @@ type
nkHiddenStdConv, # an implicit standard type conversion
nkHiddenSubConv, # an implicit type conversion from a subtype
# to a supertype
nkHiddenCallConv, # an implicit type conversion via a type converter
nkConv, # a type conversion
nkCast, # a type cast
nkStaticExpr, # a static expr
@ -452,12 +455,12 @@ type
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mSlice,
mConTArr, mConTT, mSlice,
mFields, mFieldPairs, mOmpParFor,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mRand,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mRand,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mNewStringOfCap,
mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
@ -466,18 +469,18 @@ type
mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
mFloat, mFloat32, mFloat64, mFloat128,
mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo
# things that we can evaluate safely at compile time, even if not asked for it:
@ -520,7 +523,7 @@ type
TNodeSeq* = seq[PNode]
PType* = ref TType
PSym* = ref TSym
TNode*{.final.} = object # on a 32bit machine, this takes 32 bytes
TNode*{.final, acyclic.} = object # on a 32bit machine, this takes 32 bytes
typ*: PType
comment*: string
info*: TLineInfo
@ -591,6 +594,7 @@ type
TLib* = object of lists.TListEntry # also misused for headers!
kind*: TLibKind
generated*: bool # needed for the backends:
isOverriden*: bool
name*: PRope
path*: PNode # can be a string literal!
@ -605,7 +609,7 @@ type
PInstantiation* = ref TInstantiation
PLib* = ref TLib
TSym* = object of TIdObj
TSym* {.acyclic.} = object of TIdObj
# proc and type instantiations are cached in the generic symbol
case kind*: TSymKind
of skType:
@ -653,7 +657,8 @@ type
constraint*: PNode # additional constraints like 'lit|result'
TTypeSeq* = seq[PType]
TType* = object of TIdObj # types are identical iff they have the
TType* {.acyclic.} = object of TIdObj # \
# types are identical iff they have the
# same id; there may be multiple copies of a type
# in memory!
kind*: TTypeKind # kind of type
@ -759,7 +764,7 @@ const
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit}
nkCommand, nkCallStrLit, nkHiddenCallConv}
nkLambdaKinds* = {nkLambda, nkDo}
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}

4
compiler/astalgo.nim Executable file → Normal file
View file

@ -156,6 +156,10 @@ proc skipConv*(n: PNode): PNode =
result = n.sons[1]
else: result = n
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
proc SameValue*(a, b: PNode): bool =
result = false
case a.kind

View file

@ -60,7 +60,7 @@ iterator chosen(packages: PStringTable): string =
proc addBabelPath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p):
Message(info, hintPath, p)
if gVerbosity >= 1: Message(info, hintPath, p)
lists.PrependStr(options.lazyPaths, p)
proc addPathWithNimFiles(p: string, info: TLineInfo) =
@ -83,7 +83,7 @@ proc addPathRec(dir: string, info: TLineInfo) =
if k == pcDir and p[pos] != '.':
addPackage(packages, p)
for p in packages.chosen:
addPathWithNimFiles(p, info)
addBabelPath(p, info)
proc babelPath*(path: string, info: TLineInfo) =
addPathRec(path, info)

0
compiler/bitsets.nim Executable file → Normal file
View file

4
compiler/c2nim/c2nim.nim Executable file → Normal file
View file

@ -1,7 +1,7 @@
#
#
# c2nim - C to Nimrod source converter
# (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,7 +15,7 @@ const
Version = NimrodVersion
Usage = """
c2nim - C to Nimrod source converter
(c) 2012 Andreas Rumpf
(c) 2013 Andreas Rumpf
Usage: c2nim [options] inputfile [options]
Options:
-o, --out:FILE set output filename

0
compiler/c2nim/clex.nim Executable file → Normal file
View file

11
compiler/c2nim/cparse.nim Executable file → Normal file
View file

@ -955,15 +955,22 @@ proc enumSpecifier(p: var TParser): PNode =
result = newNodeP(nkConstSection, p)
getTok(p, result)
var i = 0
var hasUnknown = false
while true:
var name = skipIdentExport(p)
var val: PNode
if p.tok.xkind == pxAsgn:
getTok(p, name)
val = constantExpression(p)
if val.kind == nkIntLit: i = int(val.intVal)+1
else: parMessage(p, errXExpected, "int literal")
if val.kind == nkIntLit:
i = int(val.intVal)+1
hasUnknown = false
else:
hasUnknown = true
else:
if hasUnknown:
parMessage(p, warnUser, "computed const value may be wrong: " &
name.renderTree)
val = newIntNodeP(nkIntLit, i, p)
inc(i)
var c = createConst(name, ast.emptyNode, val, p)

0
compiler/c2nim/cpp.nim Executable file → Normal file
View file

0
compiler/c2nim/nimrod.cfg Executable file → Normal file
View file

14
compiler/c2nim/tests/systest.c Executable file → Normal file
View file

@ -9,6 +9,20 @@ extern "C" {
# endif
#endif
enum
{
/* 8bit, color or not */
CV_LOAD_IMAGE_UNCHANGED =-1,
/* 8bit, gray */
CV_LOAD_IMAGE_GRAYSCALE =0,
/* ?, color */
CV_LOAD_IMAGE_COLOR =1,
/* any depth, ? */
CV_LOAD_IMAGE_ANYDEPTH =2,
/* ?, any color */
CV_LOAD_IMAGE_ANYCOLOR =4
};
typedef void (*callback_t) (int rc);
typedef const char* (*callback2)(int rc, long L, const char* buffer);

0
compiler/c2nim/tests/systest2.c Executable file → Normal file
View file

View file

@ -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.

269
compiler/ccgexprs.nim Executable file → Normal file
View file

@ -195,6 +195,46 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
addrLoc(dest), rdLoc(src))
if needToKeepAlive in flags: keepAlive(p, dest)
proc asgnComplexity(n: PNode): int =
if n != nil:
case n.kind
of nkSym: result = 1
of nkRecCase:
# 'case objects' are too difficult to inline their assignment operation:
result = 100
of nkRecList:
for t in items(n):
result += asgnComplexity(t)
else: nil
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
result.k = locField
result.s = a.s
result.t = t
result.r = rdLoc(a).con(".").con(field)
result.heapRoot = a.heapRoot
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
for i in 0 .. <dest.t.len:
let t = dest.t.sons[i]
let field = ropef("Field$1", i.toRope)
genAssignment(p, optAsgnLoc(dest, t, field),
optAsgnLoc(src, t, field), flags)
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
t: PNode) =
if t == nil: return
case t.kind
of nkSym:
let field = t.sym
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
optAsgnLoc(src, field.typ, field.loc.r), flags)
of nkRecList:
for child in items(t): genOptAsgnObject(p, dest, src, flags, child)
else: nil
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# Consider:
# type TMyFastString {.shallow.} = string
@ -251,10 +291,29 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
addrLoc(dest), rdLoc(src))
if needToKeepAlive in flags: keepAlive(p, dest)
of tyTuple, tyObject, tyProc:
of tyProc:
if needsComplexAssignment(dest.t):
# optimize closure assignment:
let a = optAsgnLoc(dest, dest.t, "ClEnv".toRope)
let b = optAsgnLoc(src, dest.t, "ClEnv".toRope)
genRefAssign(p, a, b, flags)
linefmt(p, cpsStmts, "$1.ClPrc = $2.ClPrc;$n", rdLoc(dest), rdLoc(src))
else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyTuple:
if needsComplexAssignment(dest.t):
if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags)
else: genGenericAsgn(p, dest, src, flags)
else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyObject:
# XXX: check for subtyping?
if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags)
if asgnComplexity(dest.t.n) <= 4:
discard getTypeDesc(p.module, dest.t)
genOptAsgnObject(p, dest, src, flags, dest.t.n)
else:
genGenericAsgn(p, dest, src, flags)
else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyArray, tyArrayConstr:
@ -574,6 +633,28 @@ proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = a.t
proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var
a: TLoc
i: int
initLocExpr(p, e.sons[0], a)
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = a.t
var r = rdLoc(a)
case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
when false:
if ty.n != nil:
var field = ty.n.sons[i].sym
if field == nil: InternalError(e.info, "genTupleElem")
if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
else:
appf(r, ".Field$1", [toRope(i)])
putIntoDest(p, d, ty.sons[i], r)
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
var ty = genRecordFieldAux(p, e, d, a)
@ -598,38 +679,42 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var
a: TLoc
i: int
initLocExpr(p, e.sons[0], a)
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = a.t
var r = rdLoc(a)
case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
when false:
if ty.n != nil:
var field = ty.n.sons[i].sym
if field == nil: InternalError(e.info, "genTupleElem")
if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
else:
appf(r, ".Field$1", [toRope(i)])
putIntoDest(p, d, ty.sons[i], r)
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
var test, u, v: TLoc
for i in countup(1, sonsLen(e) - 1):
var it = e.sons[i]
assert(it.kind in nkCallKinds)
assert(it.sons[0].kind == nkSym)
let op = it.sons[0].sym
if op.magic == mNot: it = it.sons[1]
assert(it.sons[2].kind == nkSym)
initLoc(test, locNone, it.typ, OnStack)
InitLocExpr(p, it.sons[1], u)
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
v.r = ropef("$1.$2", [obj, it.sons[2].sym.loc.r])
genInExprAux(p, it, u, v, test)
let id = NodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
else: con("TMP", toRope(id))
if op.magic == mNot:
linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
rdLoc(test), strLit)
else:
linefmt(p, cpsStmts,
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
rdLoc(test), strLit)
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
var
a, u, v, test: TLoc
f, field, op: PSym
ty: PType
r, strLit: PRope
id: int
it: PNode
if optFieldCheck in p.options:
var
a: TLoc
f, field: PSym
ty: PType
r: PRope
ty = genRecordFieldAux(p, e.sons[0], d, a)
r = rdLoc(a)
f = e.sons[0].sons[1].sym
@ -643,30 +728,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
if field == nil: InternalError(e.info, "genCheckedRecordField")
if field.loc.r == nil:
InternalError(e.info, "genCheckedRecordField") # generate the checks:
for i in countup(1, sonsLen(e) - 1):
it = e.sons[i]
assert(it.kind in nkCallKinds)
assert(it.sons[0].kind == nkSym)
op = it.sons[0].sym
if op.magic == mNot: it = it.sons[1]
assert(it.sons[2].kind == nkSym)
initLoc(test, locNone, it.typ, OnStack)
InitLocExpr(p, it.sons[1], u)
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
genInExprAux(p, it, u, v, test)
id = NodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId)
if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
else: strLit = con("TMP", toRope(id))
if op.magic == mNot:
linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
rdLoc(test), strLit)
else:
linefmt(p, cpsStmts,
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
rdLoc(test), strLit)
genFieldCheck(p, e, r, field)
app(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r)
else:
@ -913,10 +975,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = x;
let seqAppendPattern = if gCmd != cmdCompileToCpp:
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
var a, b, dest: TLoc
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
@ -935,20 +996,12 @@ proc genReset(p: BProc, n: PNode) =
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
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)
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
var sizeExpr = sizeExpr
let refType = skipTypes(a.t, abstractVarRange)
var b: TLoc
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:
if sizeExpr.isNil:
sizeExpr = ropef("sizeof($1)",
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
let args = [getTypeDesc(p.module, reftype),
@ -965,9 +1018,20 @@ proc genNew(p: BProc, e: PNode) =
else:
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)
let bt = skipTypes(refType.sons[0], abstractRange)
genObjectInit(p, cpsStmts, bt, a, false)
proc genNew(p: BProc, e: PNode) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
# 'genNew' also handles 'unsafeNew':
if e.len == 3:
var se: TLoc
InitLocExpr(p, e.sons[2], se)
rawGenNew(p, a, se.rdLoc)
else:
rawGenNew(p, a, nil)
proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype),
@ -975,7 +1039,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap)
if dest.s == OnHeap and usesNativeGC():
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc)
else:
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
else:
@ -988,6 +1055,44 @@ proc genNewSeq(p: BProc, e: PNode) =
InitLocExpr(p, e.sons[2], b)
genNewSeqAux(p, a, b.rdLoc)
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc
var t = e.typ.skipTypes(abstractInst)
getTemp(p, t, tmp)
let isRef = t.kind == tyRef
var r = rdLoc(tmp)
if isRef:
rawGenNew(p, tmp, nil)
t = t.sons[0].skipTypes(abstractInst)
r = ropef("(*$1)", r)
# XXX object initialization? but not necessary for temps, is it?
discard getTypeDesc(p.module, t)
for i in 1 .. <e.len:
let it = e.sons[i]
var tmp2: TLoc
tmp2.r = r
var field: PSym = nil
var ty = t
while ty != nil:
field = lookupInRecord(ty.n, it.sons[0].sym.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
ty = GetUniqueType(ty.sons[0])
if field == nil or field.loc.r == nil: InternalError(e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options:
genFieldCheck(p, it.sons[2], r, field)
app(tmp2.r, ".")
app(tmp2.r, field.loc.r)
tmp2.k = locTemp
tmp2.t = field.loc.t
tmp2.s = onHeap
tmp2.heapRoot = tmp.r
expr(p, it.sons[1], tmp2)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {})
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
var arr: TLoc
if d.k == locNone:
@ -995,7 +1100,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
# generate call to newSeq before adding the elements per hand:
genNewSeqAux(p, d, intLiteral(sonsLen(t)))
for i in countup(0, sonsLen(t) - 1):
initLoc(arr, locExpr, elemType(skipTypes(t.typ, abstractInst)), OnHeap)
initLoc(arr, locExpr, elemType(skipTypes(t.typ, typedescInst)), OnHeap)
arr.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
arr.s = OnHeap # we know that sequences are on the heap
expr(p, t.sons[i], arr)
@ -1226,8 +1331,14 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons
initLocExpr(p, e.sons[2], a)
# do not emit the set, but generate a bunch of comparisons; and if we do
# so, we skip the unnecessary range check: This is a semantical extension
# that code now relies on. :-/ XXX
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
e.sons[2].sons[0]
else:
e.sons[2]
initLocExpr(p, ea, a)
initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(")
var length = sonsLen(e.sons[1])
@ -1467,8 +1578,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNewFinalize: genNewFinalize(p, e)
of mNewSeq: genNewSeq(p, e)
of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))",
[getTypeDesc(p.module, e.sons[1].typ)]))
[getTypeDesc(p.module, t)]))
of mChr: genCast(p, e, d)
of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@ -1755,6 +1867,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
exprComplexConst(p, e, d)
else:
genTupleConstr(p, e, d)
of nkObjConstr: genObjConstr(p, e, d)
of nkCast: genCast(p, e, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d)
of nkHiddenAddr, nkAddr: genAddr(p, e, d)

View file

@ -11,7 +11,7 @@
## is needed for incremental compilation.
import
ast, astalgo, ropes, options, strutils, lexbase, msgs, cgendata, rodutils,
ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
intsets, platform, llstream
# Careful! Section marks need to contain a tabulator so that they cannot
@ -45,11 +45,8 @@ const
]
NimMergeEndMark = "/*\tNIM_merge_END:*/"
template mergeSectionsEnabled: expr =
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
proc genSectionStart*(fs: TCFileSection): PRope =
if mergeSectionsEnabled:
if compilationCachePresent:
result = toRope(tnl)
app(result, "/*\t")
app(result, CFileSectionNames[fs])
@ -57,11 +54,11 @@ proc genSectionStart*(fs: TCFileSection): PRope =
app(result, tnl)
proc genSectionEnd*(fs: TCFileSection): PRope =
if mergeSectionsEnabled:
if compilationCachePresent:
result = toRope(NimMergeEndMark & tnl)
proc genSectionStart*(ps: TCProcSection): PRope =
if mergeSectionsEnabled:
if compilationCachePresent:
result = toRope(tnl)
app(result, "/*\t")
app(result, CProcSectionNames[ps])
@ -69,7 +66,7 @@ proc genSectionStart*(ps: TCProcSection): PRope =
app(result, tnl)
proc genSectionEnd*(ps: TCProcSection): PRope =
if mergeSectionsEnabled:
if compilationCachePresent:
result = toRope(NimMergeEndMark & tnl)
proc writeTypeCache(a: TIdTable, s: var string) =
@ -122,8 +119,8 @@ proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = lexbase.HandleCR(L, pos)
of LF: pos = lexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
@ -132,8 +129,8 @@ proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = lexbase.HandleCR(L, pos)
of LF: pos = lexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
@ -156,11 +153,11 @@ when false:
while true:
case buf[pos]
of CR:
pos = lexbase.HandleCR(L, pos)
pos = nimlexbase.HandleCR(L, pos)
buf = L.buf
result.data.add(tnl)
of LF:
pos = lexbase.HandleLF(L, pos)
pos = nimlexbase.HandleLF(L, pos)
buf = L.buf
result.data.add(tnl)
of '\0':
@ -182,11 +179,11 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
while true:
case buf[pos]
of CR:
pos = lexbase.HandleCR(L, pos)
pos = nimlexbase.HandleCR(L, pos)
buf = L.buf
r.add(tnl)
of LF:
pos = lexbase.HandleLF(L, pos)
pos = nimlexbase.HandleLF(L, pos)
buf = L.buf
r.add(tnl)
of '\0':

41
compiler/ccgstmts.nim Executable file → Normal file
View file

@ -16,7 +16,8 @@ const
# above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) =
if gSelectedGc == gcMarkAndSweep and containsGarbageCollectedRef(v.loc.t):
if gSelectedGc in {gcMarkAndSweep, gcGenerational} and
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
let prc = genTraverseProcForGlobal(p.module, v)
@ -44,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else:
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple")
if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
field.r = ropef("$1.$2",
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
@ -63,19 +64,23 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
result = len(p.blocks)
setlen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope)
result = b.label
proc blockBody(b: var TBlock): PRope {.inline.} =
return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts])
proc blockBody(b: var TBlock): PRope =
result = b.sections[cpsLocals]
if b.frameLen > 0:
result.appf("F.len+=$1;$n", b.frameLen.toRope)
result.app(b.sections[cpsInit])
result.app(b.sections[cpsStmts])
proc endBlock(p: BProc, blockEnd: PRope) =
let topBlock = p.blocks.len - 1
let topBlock = p.blocks.len-1
# the block is merged into the parent block
app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody)
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
setlen(p.blocks, topBlock)
# this is done after the block is popped so $n is
# properly indented when pretty printing is enabled
@ -83,10 +88,13 @@ proc endBlock(p: BProc, blockEnd: PRope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let blockEnd = if p.blocks[topBlock].label != nil:
var blockEnd = if p.blocks[topBlock].label != nil:
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
else:
~"}$n"
let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0:
blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@ -773,7 +781,7 @@ var
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
if optEndb in p.Options:
if optEndb in p.Options:
if t.kind == nkExprColonExpr:
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal)
@ -783,7 +791,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
genLineDir(p, t) # BUGFIX
appcg(p.module, gBreakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) =
@ -795,16 +803,13 @@ proc genWatchpoint(p: BProc, n: PNode) =
[a.addrLoc, makeCString(renderTree(n.sons[1])),
genTypeInfo(p.module, typ)])
proc genPragma(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
proc genPragma(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
case whichPragma(it)
of wEmit:
genEmit(p, it)
of wBreakpoint:
genBreakPoint(p, it)
of wWatchpoint:
genWatchpoint(p, it)
of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it)
of wWatchpoint: genWatchpoint(p, it)
else: nil
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =

0
compiler/ccgthreadvars.nim Executable file → Normal file
View file

View file

@ -59,7 +59,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
if typ == nil: return
var p = c.p
case typ.kind
of tyGenericInst, tyGenericBody:
of tyGenericInst, tyGenericBody, tyTypeDesc:
genTraverseProc(c, accessor, lastSon(typ))
of tyArrayConstr, tyArray:
let arraySize = lengthOrd(typ.sons[0])
@ -111,10 +111,11 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p
assert typ.kind != tyTypedesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ)
else:
if skipTypes(typ.sons[0], abstractInst).kind in {tyArrayConstr, tyArray}:
if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
# C's arrays are broken beyond repair:
genTraverseProc(c, "a".toRope, typ.sons[0])
else:

22
compiler/ccgtypes.nim Executable file → Normal file
View file

@ -193,8 +193,8 @@ proc mapType(typ: PType): TCTypeKind =
of 8: result = ctInt64
else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef:
var base = skipTypes(typ.sons[0], abstractInst)
of tyPtr, tyVar, tyRef:
var base = skipTypes(typ.sons[0], typedescInst)
case base.kind
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
else: result = ctPtr
@ -208,7 +208,7 @@ proc mapType(typ: PType): TCTypeKind =
else: InternalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, abstractInst).kind == tyArray: result = ctPtr
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
else: result = mapType(typ)
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope
@ -224,10 +224,10 @@ proc isInvalidReturnType(rettype: PType): bool =
else:
case mapType(rettype)
of ctArray:
result = not (skipTypes(rettype, abstractInst).kind in
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyRef, tyPtr})
of ctStruct:
result = needsComplexAssignment(skipTypes(rettype, abstractInst))
result = needsComplexAssignment(skipTypes(rettype, typedescInst))
else: result = false
const
@ -253,7 +253,7 @@ proc getGlobalTempName(): PRope =
result = rfmt(nil, "TMP$1", toRope(backendId()))
proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, abstractInst)
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
if tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
@ -280,13 +280,13 @@ proc fillResult(param: PSym) =
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
when false:
if t.Kind in {tyRef, tyPtr, tyVar}:
var b = skipTypes(t.sons[0], abstractInst)
var b = skipTypes(t.sons[0], typedescInst)
if b.kind == tySet and mapSetType(b) == ctArray:
return getTypeDescAux(m, b, check)
result = getTypeDescAux(m, t, check)
proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar}).kind notin {tyArray, tyOpenArray}:
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
result = OnStack
else:
result = OnUnknown
@ -572,7 +572,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
assert(CacheGetType(m.typeCache, t) == nil)
IdTablePut(m.typeCache, t, con(result, "*"))
if not isImportedType(t):
if skipTypes(t.sons[0], abstractInst).kind != tyEmpty:
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const
cppSeq = "struct $2 : #TGenericSeq {$n"
cSeq = "struct $2 {$n" &
@ -744,7 +744,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
if objType.sym == nil:
InternalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [
toRope(objType.sym.name.s), toRope(d.name.s)])
toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
discard cgsym(m, "TNimNode")
@ -915,7 +915,7 @@ include ccgtrav
proc genTypeInfo(m: BModule, typ: PType): PRope =
var t = getUniqueType(typ)
result = ropef("NTI$1", [toRope(t.id)])
let owner = typ.skipTypes(abstractPtrs).owner.getModule
let owner = typ.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
# make sure the type info is created in the owner module
discard genTypeInfo(owner.bmod, typ)

4
compiler/ccgutils.nim Executable file → Normal file
View file

@ -80,13 +80,13 @@ proc GetUniqueType*(key: PType): PType =
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``.
result = key
of tyEmpty, tyNil, tyExpr, tyStmt, tyTypeDesc, tyPointer, tyString,
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
tyCString, tyNone, tyBigNum:
result = gCanonicalTypes[k]
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyGenericParam, tyTypeClass:
of tyGenericParam, tyTypeClass, tyTypeDesc:
InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key))

41
compiler/cgen.nim Executable file → Normal file
View file

@ -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.
@ -269,18 +269,18 @@ proc genCLineDir(r: var PRope, filename: string, line: int) =
proc genCLineDir(r: var PRope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm)
proc genLineDir(p: BProc, t: PNode) =
proc genLineDir(p: BProc, t: PNode) =
var line = t.info.safeLineNm
if optEmbedOrigSrc in gGlobalOptions:
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "#endb($1);$n", toRope(line))
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "#endb($1, $2);$n",
line.toRope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.Options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename)
@ -470,12 +470,13 @@ proc localDebugInfo(p: BProc, s: PSym) =
# XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = con("&", s.loc.r)
if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
lineF(p, cpsInit,
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
[toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
[p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
inc(p.frameLen)
inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen
proc assignLocalVar(p: BProc, s: PSym) =
#assert(s.loc.k == locNone) // not yet assigned
@ -488,7 +489,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
line(p, cpsLocals, decl)
@ -574,6 +575,8 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
if gVerbosity >= 2:
MsgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil
for i in countup(0, high(s)):
inc(m.labels)
@ -693,10 +696,11 @@ proc retIsNotVoid(s: PSym): bool =
proc initFrame(p: BProc, procname, filename: PRope): PRope =
discard cgsym(p.module, "pushFrame")
if p.frameLen > 0:
if p.maxFrameLen > 0:
discard cgsym(p.module, "TVarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3)$N",
procname, filename, p.frameLen.toRope)
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
procname, filename, p.maxFrameLen.toRope,
p.blocks[0].frameLen.toRope)
else:
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
@ -890,6 +894,12 @@ proc getFileHeader(cfilenoext: string): PRope =
result = getCopyright(cfilenoext)
addIntTypes(result)
proc genFilenames(m: BModule): PRope =
discard cgsym(m, "dbgRegisterFilename")
result = nil
for i in 0.. <fileInfos.len:
result.appf("dbgRegisterFilename($1);$n", fileInfos[i].projPath.makeCString)
proc genMainProc(m: BModule) =
const
CommonMainBody =
@ -948,6 +958,8 @@ proc genMainProc(m: BModule) =
nimMain = PosixNimMain
otherMain = PosixCMain
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions:
gBreakpoints.app(m.genFilenames)
let initStackBottomCall = if emulatedThreadVars() or
platform.targetOS == osStandalone: "".toRope
@ -1244,7 +1256,7 @@ proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
let cfilenoext = changeFileExt(cfile, "")
if mergeRequired(m):
if mergeRequired(m) and sfMainModule notin m.module.flags:
mergeFiles(cfile, m)
genInitCode(m)
finishTypeDescriptions(m)
@ -1254,8 +1266,7 @@ proc updateCachedModule(m: BModule) =
addFileToLink(cfilenoext)
proc cgenCaasUpdate* =
# XXX(zah): clean-up the fromCache mess
proc updateCachedModules* =
for m in cgenModules():
if m.fromCache: m.updateCachedModule

View file

@ -54,9 +54,10 @@ type
id*: int # the ID of the label; positive means that it
label*: PRope # generated text for the label
# nil if label is not used
nestedTryStmts*: int # how many try statements is it nested into
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to
@ -74,9 +75,7 @@ type
options*: TOptions # options that should be used for code
# generation; this is the same as prc.options
# unless prc == nil
frameLen*: int # current length of frame descriptor
sendClosure*: PType # closure record type that we pass
receiveClosure*: PType # closure record type that we get
maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
gcFrameId*: natural # for the GC stack marking

4
compiler/cgmeth.nim Executable file → Normal file
View file

@ -108,8 +108,8 @@ proc methodDef*(s: PSym, fromCache: bool) =
proc relevantCol(methods: TSymSeq, col: int): bool =
# returns true iff the position is relevant
var t = methods[0].typ.sons[col]
if skipTypes(t, skipPtrs).kind == tyObject:
var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in countup(1, high(methods)):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t):

0
compiler/charsets.nim Executable file → Normal file
View file

37
compiler/commands.nim Executable file → Normal file
View file

@ -65,8 +65,13 @@ proc writeCommandLineUsage() =
MsgWriteln(getCommandLineDesc())
helpWritten = true
proc addPrefix(switch: string): string =
if len(switch) == 1: result = "-" & switch
else: result = "--" & switch
proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
LocalError(info, errInvalidCmdLineOption, switch)
if switch == " ": LocalError(info, errInvalidCmdLineOption, "-")
else: LocalError(info, errInvalidCmdLineOption, addPrefix(switch))
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
info: TLineInfo) =
@ -98,10 +103,10 @@ proc ProcessOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdlinePass,
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
proc ExpectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": LocalError(info, errCmdLineArgExpected, switch)
if arg == "": LocalError(info, errCmdLineArgExpected, addPrefix(switch))
proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": LocalError(info, errCmdLineNoArgExpected, switch)
if arg != "": LocalError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
info: TLineInfo) =
@ -143,6 +148,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
of "refc": result = gSelectedGC == gcRefc
of "v2": result = gSelectedGC == gcV2
of "markandsweep": result = gSelectedGC == gcMarkAndSweep
of "generational": result = gSelectedGC == gcGenerational
of "none": result = gSelectedGC == gcNone
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "opt":
@ -190,8 +196,13 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "patterns": result = contains(gOptions, optPatterns)
else: InvalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string): string =
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath,
proc processPath(path: string, notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or
'$' in path or path[0] == '.':
path
else:
options.gProjectPath / path
result = UnixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
@ -206,6 +217,11 @@ proc track(arg: string, info: TLineInfo) =
LocalError(info, errInvalidNumber, a[2])
msgs.addCheckpoint(newLineInfo(a[0], line, column))
proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}:
expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg)
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
var
theOS: TSystemOS
@ -218,7 +234,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "babelpath":
if pass in {passCmd2, passPP}:
expectArg(switch, arg, pass, info)
let path = processPath(arg)
let path = processPath(arg, notRelativeToProj=true)
babelpath(path, info)
of "excludepath":
expectArg(switch, arg, pass, info)
@ -280,6 +296,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "markandsweep":
gSelectedGC = gcMarkAndSweep
defineSymbol("gcmarkandsweep")
of "generational":
gSelectedGC = gcGenerational
defineSymbol("gcgenerational")
of "none":
gSelectedGC = gcNone
defineSymbol("nogc")
@ -437,9 +456,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "genscript":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenScript)
of "lib":
of "lib":
expectArg(switch, arg, pass, info)
libpath = processPath(arg)
libpath = processPath(arg, notRelativeToProj=true)
of "putenv":
expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info)
@ -471,6 +490,8 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "listfullpaths":
expectNoArg(switch, arg, pass, info)
gListFullPaths = true
of "dynliboverride":
dynlibOverride(switch, arg, pass, info)
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: InvalidCmdLineOption(pass, switch, info)

10
compiler/condsyms.nim Executable file → Normal file
View file

@ -10,7 +10,7 @@
# This module handles the conditional symbols.
import
ast, astalgo, msgs, hashes, platform, strutils, idents
ast, astalgo, hashes, platform, strutils, idents
var gSymbols*: TStrTable
@ -35,14 +35,12 @@ proc isDefined*(symbol: PIdent): bool =
proc isDefined*(symbol: string): bool =
result = isDefined(getIdent(symbol))
proc ListSymbols*() =
iterator definedSymbolNames*: string =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
OutWriteln("-- List of currently defined symbols --")
while s != nil:
if s.position == 1: OutWriteln(s.name.s)
while s != nil:
if s.position == 1: yield s.name.s
s = nextIter(it, gSymbols)
OutWriteln("-- End of list --")
proc countDefinedSymbols*(): int =
var it: TTabIter

0
compiler/crc.nim Executable file → Normal file
View file

0
compiler/depends.nim Executable file → Normal file
View file

0
compiler/docgen.nim Executable file → Normal file
View file

View file

@ -142,10 +142,10 @@ proc getField(n: PNode; position: int): PSym =
else: nil
proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind == nkPar
InternalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets:
discard typ.getSize
for i in countup(0, sonsLen(x) - 1):
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
var it = x.sons[i]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym
@ -257,11 +257,11 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
unpackObjectAdd(x, typ.n, result)
else:
result = n
if result.kind != nkPar:
if result.kind notin {nkObjConstr, 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):
for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym

133
compiler/evals.nim Executable file → Normal file
View file

@ -249,7 +249,7 @@ proc getNullValueAux(obj: PNode, result: PNode) =
else: InternalError(result.info, "getNullValueAux")
proc getNullValue(typ: PType, info: TLineInfo): PNode =
var t = skipTypes(typ, abstractRange)
var t = skipTypes(typ, abstractRange-{tyTypeDesc})
result = emptyNode
case t.kind
of tyBool, tyEnum, tyChar, tyInt..tyInt64:
@ -273,9 +273,10 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info))
of tyTuple:
of tyTuple:
# XXX nkExprColonExpr is out of fashion ...
result = newNodeIT(nkPar, info, t)
for i in countup(0, sonsLen(t) - 1):
for i in countup(0, sonsLen(t) - 1):
var p = newNodeIT(nkExprColonExpr, info, t.sons[i])
var field = if t.n != nil: t.n.sons[i].sym else: newSym(
skField, getIdent(":tmp" & $i), t.owner, info)
@ -293,10 +294,12 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
if a.kind != nkIdentDefs: return raiseCannotEval(c, n.info)
# XXX var (x, y) = z support?
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
if a.sons[2].kind != nkEmpty:
if a.sons[2].kind != nkEmpty:
result = evalAux(c, a.sons[2], {})
if isSpecial(result): return
else:
if result.kind in {nkType..nkNilLit}:
result = result.copyNode
if isSpecial(result): return
else:
result = getNullValue(a.sons[0].typ, a.sons[0].info)
if a.sons[0].kind == nkSym:
var v = a.sons[0].sym
@ -444,29 +447,35 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
stackTrace(c, n, errIndexOutOfBounds)
else: stackTrace(c, n, errNilAccess)
proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
# a real field access; proc calls have already been transformed
# XXX: field checks!
result = evalAux(c, n.sons[0], flags)
if isSpecial(result): return
if isSpecial(result): return
var x = result
if x.kind != nkPar: return raiseCannotEval(c, n.info)
# this is performance critical:
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
#InternalError(it.info, "evalFieldAccess")
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
stackTrace(c, n, errFieldXNotFound, field.name.s)
result = emptyNode
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
when false:
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
#InternalError(it.info, "evalFieldAccess")
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
stackTrace(c, n, errFieldXNotFound, field.name.s)
result = emptyNode
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
var a = n.sons[0]
@ -896,13 +905,13 @@ proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
if sonsLen(ast) != 1:
GlobalError(code.info, errExprExpected, "multiple statements")
result = ast.sons[0]
result.typ = newType(tyExpr, c.module)
#result.typ = newType(tyExpr, c.module)
proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
var code = evalAux(c, n.sons[1], {})
result = parseString(code.getStrValue, code.info.toFilename,
code.stringStartingLine)
result.typ = newType(tyStmt, c.module)
#result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true
@ -993,10 +1002,10 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
case expandedSym.kind
of skTemplate:
let genSymOwner = if c.tos != nil and c.tos.prc != nil:
c.tos.prc
else:
c.module
let genSymOwner = if c.tos != nil and c.tos.prc != nil:
c.tos.prc
else:
c.module
result = evalTemplate(macroCall, expandedSym, genSymOwner)
of skMacro:
# At this point macroCall.sons[0] is nkSym node.
@ -1090,7 +1099,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return
addSon(a, result)
result = emptyNode
result = a
of mNAddMultiple:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@ -1098,7 +1107,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return
for i in countup(0, sonsLen(result) - 1): addSon(a, result.sons[i])
result = emptyNode
result = a
of mNDel:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@ -1336,19 +1345,27 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
cc = result
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
else: result = evalOp(m, n, a, b, cc)
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode
dec(gNestedEvals)
if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations)
case n.kind # atoms:
of nkEmpty: result = n
case n.kind
of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: result = copyNode(n) # end of atoms
of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkInfix,
nkPrefix, nkPostfix:
of nkType..nkNilLit:
# nkStrLit is VERY common in the traces, so we should avoid
# the 'copyNode' here.
result = n #.copyNode
of nkAsgn, nkFastAsgn: result = evalAsgn(c, n)
of nkCommand..nkHiddenCallConv:
result = evalMagicOrCall(c, n)
of nkCurly, nkBracket, nkRange:
of nkDotExpr: result = evalFieldAccess(c, n, flags)
of nkBracketExpr:
result = evalArrayAccess(c, n, flags)
of nkDerefExpr, nkHiddenDeref: result = evalDeref(c, n, flags)
of nkAddr, nkHiddenAddr: result = evalAddr(c, n, flags)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = evalConv(c, n)
of nkCurly, nkBracket, nkRange:
# flags need to be passed here for mNAddMultiple :-(
# XXX this is not correct in every case!
var a = copyNode(n)
@ -1370,12 +1387,23 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return
a.sons[i] = result
result = a
of nkBracketExpr: result = evalArrayAccess(c, n, flags)
of nkDotExpr: result = evalFieldAccess(c, n, flags)
of nkDerefExpr, nkHiddenDeref: result = evalDeref(c, n, flags)
of nkAddr, nkHiddenAddr: result = evalAddr(c, n, flags)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = evalConv(c, n)
of nkAsgn, nkFastAsgn: result = evalAsgn(c, n)
of nkObjConstr:
let t = skipTypes(n.typ, abstractInst)
var a: PNode
if t.kind == tyRef:
result = newNodeIT(nkRefTy, n.info, t)
a = getNullValue(t.sons[0], n.info)
addSon(result, a)
else:
a = getNullValue(t, n.info)
result = a
for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i]
if it.kind == nkExprColonExpr:
let value = evalAux(c, it.sons[1], flags)
if isSpecial(value): return value
a.sons[it.sons[0].sym.position] = value
else: return raiseCannotEval(c, n.info)
of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
of nkWhileStmt: result = evalWhile(c, n)
of nkCaseStmt: result = evalCase(c, n)
@ -1414,6 +1442,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = raiseCannotEval(c, n.info)
of nkRefTy:
result = evalAux(c, n.sons[0], flags)
of nkEmpty:
# nkEmpty occurs once in each trace that I looked at
result = n
else: InternalError(n.info, "evalAux: " & $n.kind)
if result == nil:
InternalError(n.info, "evalAux: returned nil " & $n.kind)
@ -1464,11 +1495,13 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
c.callsite = nOrig
var s = newStackFrame()
s.call = n
setlen(s.params, n.len)
var L = n.safeLen
if L == 0: L = 1
setlen(s.params, L)
# return value:
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
# setup parameters:
for i in 1 .. < n.len: s.params[i] = setupMacroParam(n.sons[i])
for i in 1 .. < L: s.params[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, sym.getBody)
result = s.params[0]
@ -1483,7 +1516,13 @@ proc myOpen(module: PSym): PPassContext =
pushStackFrame(c, newStackFrame())
result = c
proc myProcess(c: PPassContext, n: PNode): PNode =
var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode =
# don't eval errornous code:
if oldErrorCount != msgs.gErrorCounter:
oldErrorCount = msgs.gErrorCounter
return n
result = eval(PEvalContext(c), n)
const evalPass* = makePass(myOpen, nil, myProcess, myProcess)

66
compiler/extccomp.nim Executable file → Normal file
View file

@ -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.
@ -391,35 +391,8 @@ proc resetCompilationLists* =
initLinkedList(externalToCompile)
initLinkedList(toLink)
proc footprint(filename: string): TCrc32 =
result = crcFromFile(filename) ><
platform.OS[targetOS].name ><
platform.CPU[targetCPU].name ><
extccomp.CC[extccomp.ccompiler].name
proc externalFileChanged(filename: string): bool =
var crcFile = toGeneratedFile(filename, "crc")
var currentCrc = int(footprint(filename))
var f: TFile
if open(f, crcFile, fmRead):
var line = newStringOfCap(40)
if not f.readLine(line): line = "0"
close(f)
var oldCrc = parseInt(line)
result = oldCrc != currentCrc
else:
result = true
if result:
if open(f, crcFile, fmWrite):
f.writeln($currentCrc)
close(f)
proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename)
proc addFileToLink*(filename: string) =
prependStr(toLink, filename)
prependStr(toLink, filename)
# BUGFIX: was ``appendStr``
proc execExternalProgram*(cmd: string) =
@ -536,6 +509,34 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
"nimrod", quoteIfContainsWhite(getPrefixDir()),
"lib", quoteIfContainsWhite(libpath)])
proc footprint(filename: string): TCrc32 =
result = crcFromFile(filename) ><
platform.OS[targetOS].name ><
platform.CPU[targetCPU].name ><
extccomp.CC[extccomp.ccompiler].name ><
getCompileCFileCmd(filename, true)
proc externalFileChanged(filename: string): bool =
var crcFile = toGeneratedFile(filename, "crc")
var currentCrc = int(footprint(filename))
var f: TFile
if open(f, crcFile, fmRead):
var line = newStringOfCap(40)
if not f.readLine(line): line = "0"
close(f)
var oldCrc = parseInt(line)
result = oldCrc != currentCrc
else:
result = true
if result:
if open(f, crcFile, fmWrite):
f.writeln($currentCrc)
close(f)
proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename)
proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
isExternal: bool) =
var it = PStrEntry(list.head)
@ -572,7 +573,12 @@ proc CallCCompiler*(projectfile: string) =
else:
res = execProcesses(cmds, {poUseShell, poParentStreams},
gNumberOfProcessors)
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
if res != 0:
if gNumberOfProcessors <= 1:
rawMessage(errExecutionOfProgramFailed, [])
else:
rawMessage(errGenerated, " execution of an external program failed; " &
"rerun with --parallelBuild:1 to see the error message")
if optNoLinking notin gGlobalOptions:
# call the linker:
var it = PStrEntry(toLink.head)

8
compiler/filter_tmpl.nim Executable file → Normal file
View file

@ -98,7 +98,13 @@ proc parseLine(p: var TTmplParser) =
of wElif, wOf, wElse, wExcept, wFinally:
LLStreamWrite(p.outp, repeatChar(p.indent - 2))
LLStreamWrite(p.outp, substr(p.x, d))
else:
of wLet, wVar, wConst, wType:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
if not p.x.contains({':', '='}):
# no inline element --> treat as block:
inc(p.indent, 2)
else:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
p.state = psDirective

0
compiler/filters.nim Executable file → Normal file
View file

0
compiler/idents.nim Executable file → Normal file
View file

0
compiler/importer.nim Executable file → Normal file
View file

100
compiler/ecmasgen.nim → compiler/jsgen.nim Executable file → Normal file
View file

@ -20,22 +20,22 @@ import
# implementation
type
TEcmasGen = object of TPassContext
TJSGen = object of TPassContext
module: PSym
BModule = ref TEcmasGen
TEcmasTypeKind = enum # necessary JS "types"
BModule = ref TJSGen
TJSTypeKind = enum # necessary JS "types"
etyNone, # no type
etyNull, # null type
etyProc, # proc type
etyBool, # bool type
etyInt, # Ecmascript's int
etyFloat, # Ecmascript's float
etyString, # Ecmascript's string
etyObject, # Ecmascript's reference to an object
etyInt, # JavaScript's int
etyFloat, # JavaScript's float
etyString, # JavaScript's string
etyObject, # JavaScript's reference to an object
etyBaseIndex # base + index needed
TCompRes{.final.} = object
kind: TEcmasTypeKind
kind: TJSTypeKind
com: PRope # computation part
# address if this is a (address, index)-tuple
res: PRope # result part; index if this is an
@ -44,7 +44,6 @@ type
TBlock{.final.} = object
id: int # the ID of the label; positive means that it
# has been used (i.e. the label should be emitted)
nestedTryStmts: int # how many try statements is it nested into
isLoop: bool # whether it's a 'block' or 'while'
TGlobals{.final.} = object
@ -57,12 +56,11 @@ type
TProc{.final.} = object
procDef: PNode
prc: PSym
data: PRope
locals: PRope
options: TOptions
module: BModule
g: PGlobals
BeforeRetNeeded: bool
nestedTryStmts: int
unique: int
blocks: seq[TBlock]
@ -91,7 +89,7 @@ const
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
proc mapType(typ: PType): TEcmasTypeKind =
proc mapType(typ: PType): TJSTypeKind =
var t = skipTypes(typ, abstractInst)
case t.kind
of tyVar, tyRef, tyPtr:
@ -485,10 +483,6 @@ proc genLineDir(p: var TProc, n: PNode, r: var TCompRes) =
((p.prc == nil) or not (sfPure in p.prc.flags)):
appf(r.com, "F.line = $1;$n", [toRope(line)])
proc finishTryStmt(p: var TProc, r: var TCompRes, howMany: int) =
for i in countup(1, howMany):
app(r.com, "excHandler = excHandler.prev;" & tnl)
proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
var
cond, stmt: TCompRes
@ -498,7 +492,6 @@ proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
length = len(p.blocks)
setlen(p.blocks, length + 1)
p.blocks[length].id = - p.unique
p.blocks[length].nestedTryStmts = p.nestedTryStmts
p.blocks[length].isLoop = true
labl = p.unique
gen(p, n.sons[0], cond)
@ -543,7 +536,6 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) =
if optStackTrace in p.Options: app(r.com, "framePtr = F;" & tnl)
app(r.com, "try {" & tnl)
length = sonsLen(n)
inc(p.nestedTryStmts)
genStmt(p, n.sons[0], a)
app(r.com, mergeStmt(a))
i = 1
@ -571,8 +563,6 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) =
appf(epart, "$1}$n", [mergeStmt(a)])
inc(i)
if epart != nil: appf(r.com, "} catch (EXC) {$n$1", [epart])
finishTryStmt(p, r, p.nestedTryStmts)
dec(p.nestedTryStmts)
app(r.com, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
if (i < length) and (n.sons[i].kind == nkFinally):
genStmt(p, n.sons[i].sons[0], a)
@ -605,8 +595,8 @@ proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) =
if cond.com != nil: appf(r.com, "$1;$n", [cond.com])
stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
if stringSwitch:
useMagic(p, "toEcmaStr")
appf(r.com, "switch (toEcmaStr($1)) {$n", [cond.res])
useMagic(p, "toJSStr")
appf(r.com, "switch (toJSStr($1)) {$n", [cond.res])
else:
appf(r.com, "switch ($1) {$n", [cond.res])
for i in countup(1, sonsLen(n) - 1):
@ -619,17 +609,17 @@ proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) =
v = copyNode(e.sons[0])
while (v.intVal <= e.sons[1].intVal):
gen(p, v, cond)
if cond.com != nil: internalError(v.info, "ecmasgen.genCaseStmt")
if cond.com != nil: internalError(v.info, "jsgen.genCaseStmt")
appf(r.com, "case $1: ", [cond.res])
Inc(v.intVal)
else:
gen(p, e, cond)
if cond.com != nil: internalError(e.info, "ecmasgen.genCaseStmt")
if cond.com != nil: internalError(e.info, "jsgen.genCaseStmt")
if stringSwitch:
case e.kind
of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ",
[makeJSString(e.strVal)])
else: InternalError(e.info, "ecmasgen.genCaseStmt: 2")
else: InternalError(e.info, "jsgen.genCaseStmt: 2")
else:
appf(r.com, "case $1: ", [cond.res])
genStmt(p, lastSon(it), stmt)
@ -637,7 +627,7 @@ proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkElse:
genStmt(p, it.sons[0], stmt)
appf(r.com, "default: $n$1break;$n", [mergeStmt(stmt)])
else: internalError(it.info, "ecmasgen.genCaseStmt")
else: internalError(it.info, "jsgen.genCaseStmt")
appf(r.com, "}$n", [])
proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes)
@ -655,7 +645,6 @@ proc genBlock(p: var TProc, n: PNode, r: var TCompRes) =
sym.loc.a = idx
setlen(p.blocks, idx + 1)
p.blocks[idx].id = - p.unique # negative because it isn't used yet
p.blocks[idx].nestedTryStmts = p.nestedTryStmts
labl = p.unique
if n.kind == nkBlockExpr: genStmtListExpr(p, n.sons[1], r)
else: genStmt(p, n.sons[1], r)
@ -682,7 +671,6 @@ proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) =
if idx < 0 or not p.blocks[idx].isLoop:
InternalError(n.info, "no loop to break")
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])
proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) =
@ -692,7 +680,7 @@ proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) =
case n.sons[i].Kind
of nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal)
of nkSym: app(r.com, mangleName(n.sons[i].sym))
else: InternalError(n.sons[i].info, "ecmasgen: genAsmStmt()")
else: InternalError(n.sons[i].info, "jsgen: genAsmStmt()")
proc genIfStmt(p: var TProc, n: PNode, r: var TCompRes) =
var
@ -758,7 +746,7 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
nkCommand, nkHiddenCallConv, nkCallStrLit}
@ -967,7 +955,8 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
elif not p.g.generatedSyms.containsOrIncl(s.id):
var r2: TCompRes
genProc(p, s, r2)
app(p.g.code, mergeStmt(r2))
app(p.locals, mergeStmt(r2))
#app(r.com, mergeStmt(r2))
else:
if s.loc.r == nil:
InternalError(n.info, "symbol has no generated name: " & s.name.s)
@ -1152,6 +1141,8 @@ proc genConstant(p: var TProc, c: PSym, r: var TCompRes) =
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
genLineDir(p, c.ast, r)
genVarInit(p, c, c.ast, r)
app(p.g.code, r.com)
r.com = nil
when false:
proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) =
@ -1276,7 +1267,7 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
binaryStmt(p, n, r, "", "$1 += $2")
else:
binaryStmt(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)")
# XXX: make a copy of $2, because of ECMAScript's sucking semantics
# XXX: make a copy of $2, because of Javascript's sucking semantics
of mAppendSeqElem: binaryStmt(p, n, r, "", "$1.push($2)")
of mConStrStr: genConStrStr(p, n, r)
of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
@ -1367,6 +1358,21 @@ proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) =
appf(r.res, "Field$1: $2", [i.toRope, a.res])
r.res.app("}")
proc genObjConstr(p: var TProc, n: PNode, r: var TCompRes) =
# XXX inheritance?
var a: TCompRes
r.res = toRope("{")
for i in countup(0, sonsLen(n) - 1):
if i > 0: app(r.res, ", ")
var it = n.sons[i]
InternalAssert it.kind == nkExprColonExpr
gen(p, it.sons[1], a)
r.com = mergeExpr(r.com, a.com)
var f = it.sons[0].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
appf(r.res, "$1: $2", [f.loc.r, a.res])
r.res.app("}")
proc genConv(p: var TProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].typ, abstractVarRange)
@ -1395,8 +1401,8 @@ proc convStrToCStr(p: var TProc, n: PNode, r: var TCompRes) =
else:
gen(p, n.sons[0], r)
if r.res == nil: InternalError(n.info, "convStrToCStr")
useMagic(p, "toEcmaStr")
r.res = ropef("toEcmaStr($1)", [r.res])
useMagic(p, "toJSStr")
r.res = ropef("toJSStr($1)", [r.res])
proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) =
# we do an optimization here as this is likely to slow down
@ -1418,7 +1424,6 @@ proc genReturnStmt(p: var TProc, n: PNode, r: var TCompRes) =
if a.com != nil: appf(r.com, "$1;$n", mergeStmt(a))
else:
genLineDir(p, n, r)
finishTryStmt(p, r, p.nestedTryStmts)
app(r.com, "break BeforeRet;" & tnl)
proc genProcBody(p: var TProc, prc: PSym, r: TCompRes): PRope =
@ -1451,16 +1456,17 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) =
resultAsgn = nil
name = mangleName(prc)
header = generateHeader(p, prc.typ)
if (prc.typ.sons[0] != nil) and sfPure notin prc.flags:
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast.sons[resultPos].sym
resultAsgn = ropef("var $1 = $2;$n", [mangleName(resultSym),
resultAsgn = ropef("var $# = $#;$n", [mangleName(resultSym),
createVar(p, resultSym.typ, isIndirect(resultSym))])
gen(p, prc.ast.sons[resultPos], a)
if a.com != nil: appf(returnStmt, "$1;$n", [a.com])
returnStmt = ropef("return $1;$n", [a.res])
returnStmt = ropef("return $#;$n", [a.res])
genStmt(p, prc.getBody, r)
r.com = ropef("function $1($2) {$n$3$4$5}$n",
[name, header, resultAsgn, genProcBody(p, prc, r), returnStmt])
r.com = ropef("function $#($#) {$n$#$#$#$#}$n",
[name, header, p.locals, resultAsgn,
genProcBody(p, prc, r), returnStmt])
r.res = nil
#if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s
@ -1512,9 +1518,10 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil
of nkProcDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
var r2: TCompRes
genSym(p, n.sons[namePos], r2)
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
#var r2: TCompRes
genSym(p, n.sons[namePos], r)
r.res = nil
of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented")
else:
@ -1566,6 +1573,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r)
of nkPar: genTupleConstr(p, n, r)
of nkObjConstr: genObjConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr: genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
@ -1626,7 +1634,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
if m.module == nil: InternalError(n.info, "myProcess")
initProc(p, globals, m, nil, m.module.options)
genModule(p, n, r)
app(p.g.code, p.data)
app(p.g.code, p.locals)
app(p.g.code, mergeStmt(r))
proc myClose(b: PPassContext, n: PNode): PNode =
@ -1660,10 +1668,10 @@ proc myClose(b: PPassContext, n: PNode): PNode =
discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
InternalError("symbol files are not possible with the Ecmas code generator")
InternalError("symbol files are not possible with the JS code generator")
result = nil
proc myOpen(s: PSym): PPassContext =
result = newModule(s)
const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View file

@ -322,7 +322,7 @@ proc generateThunk(prc: PNode, dest: PType): PNode =
# we cannot generate a proper thunk here for GC-safety reasons (see internal
# documentation):
if gCmd == cmdCompileToEcmaScript: return prc
if gCmd == cmdCompileToJS: return prc
result = newNodeIT(nkClosure, prc.info, dest)
var conv = newNodeIT(nkHiddenStdConv, prc.info, dest)
conv.add(emptyNode)
@ -391,7 +391,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
gatherVars(o, inner, body)
# dummy closure param needed?
if inner.closureParam == nil and n.sym.typ.callConv == ccClosure:
assert tfCapturesEnv notin n.sym.typ.flags
#assert tfCapturesEnv notin n.sym.typ.flags
dummyClosureParam(o, inner)
# only transform if it really needs a closure:
if inner.closureParam != nil:
@ -443,10 +443,15 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
searchForInnerProcs(o, n.sons[i])
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkFastAsgn, ri.info)
result.add(le)
result.add(ri)
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
# mean to be able to capture string literals which have no GC header.
# However this can only happen if the capture happens through a parameter,
# which is however the only case when we generate an assignment in the first
# place.
result = newNodeI(nkAsgn, info, 2)
result.sons[0] = le
result.sons[1] = ri
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info)
@ -481,13 +486,13 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
if local.kind == skParam:
# maybe later: (sfByCopy in local.flags)
# add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local)))
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
# add support for 'up' references:
for e, field in items(scope.deps):
# add ``env.up = env2``
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
newSymNode(getClosureVar(o, e))))
newSymNode(getClosureVar(o, e)), env.info))
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if n == nil: return nil
@ -543,7 +548,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if x != nil: n.sons[i] = x
proc liftLambdas*(fn: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToEcmaScript:
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
# ignore forward declaration:
result = body
else:
@ -566,7 +571,7 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
result = ex
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToEcmaScript:
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
result = body
else:
var o = newOuterContext(module)

19
compiler/lexer.nim Executable file → Normal file
View file

@ -16,7 +16,7 @@
# DOS or Macintosh text files, even when it is not the native format.
import
hashes, options, msgs, strutils, platform, idents, lexbase, llstream,
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg
const
@ -530,10 +530,10 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR:
registerLine()
result = lexbase.HandleCR(L, pos)
result = nimlexbase.HandleCR(L, pos)
of LF:
registerLine()
result = lexbase.HandleLF(L, pos)
result = nimlexbase.HandleLF(L, pos)
else: result = pos
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
@ -559,7 +559,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
pos = HandleCRLF(L, pos)
buf = L.buf
add(tok.literal, tnl)
of lexbase.EndOfFile:
of nimlexbase.EndOfFile:
var line2 = L.linenumber
L.LineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
@ -581,7 +581,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
else:
inc(pos) # skip '"'
break
elif c in {CR, LF, lexbase.EndOfFile}:
elif c in {CR, LF, nimlexbase.EndOfFile}:
lexMessage(L, errClosingQuoteExpected)
break
elif (c == '\\') and not rawMode:
@ -675,10 +675,12 @@ proc scanComment(L: var TLexer, tok: var TToken) =
# a comment ends if the next line does not start with the # on the same
# column after only whitespace
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
var col = getColNumber(L, pos)
while true:
var lastBackslash = -1
while buf[pos] notin {CR, LF, lexbase.EndOfFile}:
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
if buf[pos] == '\\': lastBackslash = pos+1
add(tok.literal, buf[pos])
inc(pos)
@ -686,7 +688,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
# a backslash is a continuation character if only followed by spaces
# plus a newline:
while buf[lastBackslash] == ' ': inc(lastBackslash)
if buf[lastBackslash] notin {CR, LF, lexbase.EndOfFile}:
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
# false positive:
lastBackslash = -1
@ -699,6 +701,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
if buf[pos] == '#' and (col == indent or lastBackslash > 0):
tok.literal.add "\n"
col = indent
inc tok.iNumber
else:
if buf[pos] > ' ':
L.indentAhead = indent
@ -838,7 +841,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
else:
if c in OpChars:
getOperator(L, tok)
elif c == lexbase.EndOfFile:
elif c == nimlexbase.EndOfFile:
tok.toktype = tkEof
else:
tok.literal = c & ""

0
compiler/lists.nim Executable file → Normal file
View file

0
compiler/llstream.nim Executable file → Normal file
View file

0
compiler/lookups.nim Executable file → Normal file
View file

5
compiler/magicsys.nim Executable file → Normal file
View file

@ -38,7 +38,10 @@ proc newSysType(kind: TTypeKind, size: int): PType =
proc getSysSym(name: string): PSym =
result = StrTableGet(systemModule.tab, getIdent(name))
if result == nil: rawMessage(errSystemNeeds, name)
if result == nil:
rawMessage(errSystemNeeds, name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
if result.kind == skStub: loadStub(result)
proc sysTypeFromName*(name: string): PType =

68
compiler/main.nim Executable file → Normal file
View file

@ -14,7 +14,7 @@ import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, lists, condsyms, rodread, rodwrite, ropes, trees, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen, cgendata,
cgen, jsgen, cgendata, json, nversion,
platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2, service, magicsys, parser, crc, ccgutils
@ -155,7 +155,8 @@ proc compileModule(fileIdx: int32, flags: TSymFlags): PSym =
growCache gMemCacheData, fileIdx
gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(fileIdx)
var rd = handleSymbolFile(result)
#var rd = handleSymbolFile(result)
var rd: PRodReader
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
@ -251,8 +252,8 @@ proc CommandCompileToC =
compileProject()
if optCaasEnabled in gGlobalOptions:
cgenCaasUpdate()
if compilationCachePresent:
updateCachedModules()
if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
@ -301,18 +302,19 @@ when has_LLVM_Backend:
#registerPass(cleanupPass())
compileProject()
proc CommandCompileToEcmaScript =
proc CommandCompileToJS =
#incl(gGlobalOptions, optSafeCode)
setTarget(osEcmaScript, cpuEcmaScript)
setTarget(osJS, cpuJS)
#initDefines()
DefineSymbol("nimrod") # 'nimrod' is always defined
DefineSymbol("ecmascript")
DefineSymbol("ecmascript") # For backward compatibility
DefineSymbol("js")
semanticPasses()
registerPass(ecmasgenPass)
registerPass(jsgenPass)
compileProject()
proc InteractivePasses =
incl(gGlobalOptions, optSafeCode)
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines()
DefineSymbol("nimrodvm")
@ -390,6 +392,15 @@ proc wantMainModule =
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
proc requireMainModuleOption =
if optMainModule.len == 0:
Fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
proc resetMemory =
resetCompilationLists()
ccgutils.resetCaches()
@ -461,9 +472,10 @@ proc MainCommand =
gCmd = cmdCompileToC
wantMainModule()
CommandCompileToC()
of "cpp", "compiletocpp":
of "cpp", "compiletocpp":
extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gpp")
wantMainModule()
DefineSymbol("cpp")
CommandCompileToC()
@ -481,10 +493,10 @@ proc MainCommand =
CommandCompileToC()
else:
rawMessage(errInvalidCommandX, command)
of "js", "compiletoecmascript":
gCmd = cmdCompileToEcmaScript
of "js", "compiletojs":
gCmd = cmdCompileToJS
wantMainModule()
CommandCompileToEcmaScript()
CommandCompileToJS()
of "compiletollvm":
gCmd = cmdCompileToLLVM
wantMainModule()
@ -526,9 +538,30 @@ proc MainCommand =
wantMainModule()
CommandGenDepend()
of "dump":
gCmd = cmdDump
condsyms.ListSymbols()
for it in iterSearchPath(searchPaths): MsgWriteln(it)
gcmd = cmdDump
if getconfigvar("dump.format") == "json":
requireMainModuleOption()
var definedSymbols = newJArray()
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
var libpaths = newJArray()
for dir in itersearchpath(searchpaths): libpaths.elems.add(%dir)
var dumpdata = % [
(key: "version", val: %VersionAsString),
(key: "project_path", val: %gProjectFull),
(key: "defined_symbols", val: definedSymbols),
(key: "lib_paths", val: libpaths)
]
outWriteLn($dumpdata)
else:
outWriteLn("-- list of currently defined symbols --")
for s in definedSymbolNames(): outWriteLn(s)
outWriteLn("-- end of list --")
for it in iterSearchPath(searchpaths): msgWriteLn(it)
of "check":
gCmd = cmdCheck
wantMainModule()
@ -558,13 +591,14 @@ proc MainCommand =
wantMainModule()
CommandSuggest()
of "serve":
isServing = true
gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error
serve(MainCommand)
else:
rawMessage(errInvalidCommandX, command)
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun}:
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun, cmdDump}:
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
formatSize(getTotalMem())])

24
compiler/msgs.nim Executable file → Normal file
View file

@ -83,7 +83,9 @@ type
errInvalidCommandX, errXOnlyAtModuleScope,
errXNeedsParamObjectType,
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename, errXExpected,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
@ -301,6 +303,7 @@ const
errInstantiationFrom: "instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "\'$1\' expected",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
@ -506,6 +509,8 @@ var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
proc sourceLine*(i: TLineInfo): PRope
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent}
gErrorCounter*: int = 0 # counts the number of errors
@ -523,8 +528,8 @@ proc SuggestWriteln*(s: string) =
stdoutSocket.send(s & "\c\L")
proc SuggestQuit*() =
if isNil(stdoutSocket): quit(0)
else:
if not isServing: quit(0)
elif not isNil(stdoutSocket):
stdoutSocket.send("\c\L")
raise newException(ESuggestDone, "suggest done")
@ -707,6 +712,11 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
var
lastError = UnknownLineInfo()
proc writeSurroundingSrc(info: TLineInfo) =
const indent = " "
MsgWriteln(indent & info.sourceLine.data)
MsgWriteln(indent & repeatChar(info.col, ' ') & '^')
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
var frmt: string
@ -732,6 +742,8 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
coordToStr(info.col), getMessageStr(msg, arg)]
if not ignoreMsg:
MsgWriteln(s)
if optPrintSurroundingSrc and msg in errMin..errMax:
info.writeSurroundingSrc
handleError(msg, eh, s)
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
@ -771,6 +783,12 @@ proc addSourceLine*(fileIdx: int32, line: string) =
proc sourceLine*(i: TLineInfo): PRope =
if i.fileIndex < 0: return nil
if not optPreserveOrigSource and
fileInfos[i.fileIndex].lines.len == 0:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
InternalAssert i.fileIndex < fileInfos.len and
i.line <= fileInfos[i.fileIndex].lines.len

0
compiler/nimconf.nim Executable file → Normal file
View file

0
compiler/lexbase.nim → compiler/nimlexbase.nim Executable file → Normal file
View file

2
compiler/nimrod.cfg Executable file → Normal file
View file

@ -6,7 +6,7 @@ hint[XDeclaredButNotUsed]:off
path:"llvm"
path:"$projectPath/.."
path:"$nimrod/packages/docutils"
path:"$lib/packages/docutils"
define:booting

54
compiler/nimrod.dot Executable file → Normal file
View file

@ -472,32 +472,32 @@ cgen -> wordrecg;
cgen -> rnimsyn;
cgen -> treetab;
cgen -> cgmeth;
ecmasgen -> ast;
ecmasgen -> astalgo;
ecmasgen -> strutils;
ecmasgen -> nhashes;
ecmasgen -> trees;
ecmasgen -> platform;
ecmasgen -> magicsys;
ecmasgen -> extccomp;
ecmasgen -> options;
ecmasgen -> nversion;
ecmasgen -> nimsets;
ecmasgen -> msgs;
ecmasgen -> crc;
ecmasgen -> bitsets;
ecmasgen -> idents;
ecmasgen -> lists;
ecmasgen -> types;
ecmasgen -> os;
ecmasgen -> times;
ecmasgen -> ropes;
ecmasgen -> math;
ecmasgen -> passes;
ecmasgen -> ccgutils;
ecmasgen -> wordrecg;
ecmasgen -> rnimsyn;
ecmasgen -> rodread;
jsgen -> ast;
jsgen -> astalgo;
jsgen -> strutils;
jsgen -> nhashes;
jsgen -> trees;
jsgen -> platform;
jsgen -> magicsys;
jsgen -> extccomp;
jsgen -> options;
jsgen -> nversion;
jsgen -> nimsets;
jsgen -> msgs;
jsgen -> crc;
jsgen -> bitsets;
jsgen -> idents;
jsgen -> lists;
jsgen -> types;
jsgen -> os;
jsgen -> times;
jsgen -> ropes;
jsgen -> math;
jsgen -> passes;
jsgen -> ccgutils;
jsgen -> wordrecg;
jsgen -> rnimsyn;
jsgen -> rodread;
interact -> llstream;
interact -> strutils;
interact -> ropes;
@ -561,7 +561,7 @@ main -> passes;
main -> docgen;
main -> extccomp;
main -> cgen;
main -> ecmasgen;
main -> jsgen;
main -> platform;
main -> interact;
main -> nimconf;

5
compiler/nimrod.ini Executable file → Normal file
View file

@ -57,8 +57,6 @@ Files: "compiler/*.nim"
Files: "build/empty.txt"
Files: "bin/empty.txt"
Files: "packages/docutils/*.nim"
[Lib]
Files: "lib/nimbase.h"
@ -84,7 +82,8 @@ Files: "lib/wrappers/zip/libzip_all.c"
Files: "lib/windows/*.nim"
Files: "lib/posix/*.nim"
Files: "lib/ecmas/*.nim"
Files: "lib/js/*.nim"
Files: "lib/packages/docutils/*.nim"
[Other]

2
compiler/nimrod.nim Executable file → Normal file
View file

@ -60,7 +60,7 @@ proc HandleCmdLine() =
if gCmd == cmdRun:
tccgen.run()
if optRun in gGlobalOptions:
if gCmd == cmdCompileToEcmaScript:
if gCmd == cmdCompileToJS:
var ex = quoteIfContainsWhite(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & service.arguments)

10
compiler/nimsets.nim Executable file → Normal file
View file

@ -44,9 +44,9 @@ proc inSet(s: PNode, elem: PNode): bool =
return true
result = false
proc overlap(a, b: PNode): bool =
if a.kind == nkRange:
if b.kind == nkRange:
proc overlap(a, b: PNode): bool =
if a.kind == nkRange:
if b.kind == nkRange:
# X..Y and C..D overlap iff (X <= D and C <= Y)
result = leValue(a.sons[0], b.sons[1]) and
leValue(b.sons[0], a.sons[1])
@ -98,13 +98,13 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
result.typ = settype
result.info = info
e = 0
while e < high(s) * elemSize:
while e < len(s) * elemSize:
if bitSetIn(s, e):
a = e
b = e
while true:
Inc(b)
if (b > high(s) * elemSize) or not bitSetIn(s, b): break
if (b >= len(s) * elemSize) or not bitSetIn(s, b): break
Dec(b)
if a == b:
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))

2
compiler/nversion.nim Executable file → Normal file
View file

@ -18,5 +18,5 @@ const
VersionPatch* = 1
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1210" # modify this if the rod-format changes!
RodFileVersion* = "1212" # modify this if the rod-format changes!

35
compiler/options.nim Executable file → Normal file
View file

@ -68,7 +68,7 @@ type # please make sure we have under 32 options
TCommands* = enum # Nimrod's commands
# **keep binary compatible**
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToEcmaScript, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdDump,
cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging)
@ -81,7 +81,7 @@ type # please make sure we have under 32 options
cmdRun # run the project via TCC backend
TStringSeq* = seq[string]
TGCMode* = enum # the selected GC
gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2
gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
const
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
@ -99,16 +99,26 @@ var
searchPaths*, lazyPaths*: TLinkedList
outFile*: string = ""
headerFile*: string = ""
gVerbosity*: int # how verbose the compiler is
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
gWholeProject*: bool # for 'doc2': output any dependency
gWholeProject*: bool # for 'doc2': output any dependency
gEvalExpr* = "" # expression for idetools --eval
gLastCmdTime*: float # when caas is enabled, we measure each command
gListFullPaths*: bool
isServing*: bool = false
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
template compilationCachePresent*: expr =
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
template optPreserveOrigSource*: expr =
optEmbedOrigSrc in gGlobalOptions
template optPrintSurroundingSrc*: expr =
gVerbosity >= 2
const
genSubDir* = "nimcache"
NimExt* = "nim"
@ -123,6 +133,7 @@ const
# additional configuration variables:
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringtable(modeCaseInsensitive)
libpath* = ""
gProjectName* = "" # holds a name like 'nimrod'
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
@ -255,6 +266,20 @@ proc libCandidates*(s: string, dest: var seq[string]) =
else:
add(dest, s)
proc canonDynlibName(s: string): string =
let start = if s.startsWith("lib"): 3 else: 0
let ende = strutils.find(s, {'(', ')', '.'})
if ende >= 0:
result = s.substr(start, ende-1)
else:
result = s.substr(start)
proc inclDynlibOverride*(lib: string) =
gDllOverrides[lib.canonDynlibName] = "true"
proc isDynlibOverride*(lib: string): bool =
result = gDllOverrides.hasKey(lib.canonDynlibName)
proc binaryStrSearch*(x: openarray[string], y: string): int =
var a = 0
var b = len(x) - 1

View file

@ -187,21 +187,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
else:
result = arLValue
of nkDotExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
{tyVar, tyPtr, tyRef}:
result = arLValue
else:
else:
result = isAssignable(owner, n.sons[0])
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
result = arDiscriminant
of nkBracketExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
{tyVar, tyPtr, tyRef}:
result = arLValue
else:
result = isAssignable(owner, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
# Object and tuple conversions are still addressable, so we skip them
# XXX why is 'tyOpenArray' allowed here?
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
{tyOpenArray, tyTuple, tyObject}:
result = isAssignable(owner, n.sons[1])
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
# types that are equal modulo distinction preserve l-value:

2
compiler/parsecfg.nim Executable file → Normal file
View file

@ -12,7 +12,7 @@
# standard library.
import
llstream, nhashes, strutils, lexbase
llstream, nhashes, strutils, nimlexbase
type
TCfgEventKind* = enum

53
compiler/parser.nim Executable file → Normal file
View file

@ -254,15 +254,21 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
optPar(p)
eat(p, endToken)
proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode =
proc exprColonEqExpr(p: var TParser): PNode =
var a = parseExpr(p)
if p.tok.tokType == tok:
result = newNodeP(kind, p)
if p.tok.tokType == tkColon:
result = newNodeP(nkExprColonExpr, p)
getTok(p)
#optInd(p, result)
addSon(result, a)
addSon(result, parseExpr(p))
else:
elif p.tok.tokType == tkEquals:
result = newNodeP(nkExprEqExpr, p)
getTok(p)
#optInd(p, result)
addSon(result, a)
addSon(result, parseExpr(p))
else:
result = a
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
@ -309,14 +315,13 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
optInd(p, a)
eat(p, endTok)
proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind,
endTok, sepTok: TTokType, result: PNode) =
proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p)
optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and
(p.tok.tokType != tkSad) and (p.tok.tokType != tkInd):
var a = exprColonEqExpr(p, elemKind, sepTok)
var a = exprColonEqExpr(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
@ -324,10 +329,10 @@ proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind,
optPar(p)
eat(p, endTok)
proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind,
endTok, sepTok: TTokType): PNode =
proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
endTok: TTokType): PNode =
result = newNodeP(kind, p)
exprColonEqExprListAux(p, elemKind, endTok, sepTok, result)
exprColonEqExprListAux(p, endTok, result)
proc setOrTableConstr(p: var TParser): PNode =
result = newNodeP(nkCurly, p)
@ -338,7 +343,7 @@ proc setOrTableConstr(p: var TParser): PNode =
result.kind = nkTableConstr
else:
while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}:
var a = exprColonEqExpr(p, nkExprColonExpr, tkColon)
var a = exprColonEqExpr(p)
if a.kind == nkExprColonExpr: result.kind = nkTableConstr
addSon(result, a)
if p.tok.tokType != tkComma: break
@ -471,16 +476,15 @@ proc identOrLiteral(p: var TParser): PNode =
of tkNil:
result = newNodeP(nkNilLit, p)
getTok(p)
of tkParLe:
of tkParLe:
# () constructor
result = exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon)
of tkCurlyLe:
result = exprColonEqExprList(p, nkPar, tkParRi)
of tkCurlyLe:
# {} constructor
result = setOrTableConstr(p)
of tkBracketLe:
of tkBracketLe:
# [] constructor
result = exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi,
tkColon)
result = exprColonEqExprList(p, nkBracket, tkBracketRi)
of tkCast:
result = parseCast(p)
else:
@ -496,8 +500,11 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
var a = result
result = newNodeP(nkCall, p)
addSon(result, a)
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
parseDoBlocks(p, result)
exprColonEqExprListAux(p, tkParRi, result)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
else:
parseDoBlocks(p, result)
of tkDo:
var a = result
result = newNodeP(nkCall, p)
@ -564,7 +571,7 @@ proc parsePragma(p: var TParser): PNode =
optInd(p, result)
while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and
(p.tok.tokType != tkEof) and (p.tok.tokType != tkSad):
var a = exprColonEqExpr(p, nkExprColonExpr, tkColon)
var a = exprColonEqExpr(p)
addSon(result, a)
if p.tok.tokType == tkComma:
getTok(p)
@ -739,7 +746,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
proc isExprStart(p: TParser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
tkProc, tkIterator, tkBind,
tkProc, tkIterator, tkBind, tkAddr,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared:
result = true
@ -1200,9 +1207,9 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
addSon(result, ast.emptyNode)
indAndComment(p, result) # XXX: document this in the grammar!
proc newCommentStmt(p: var TParser): PNode =
proc newCommentStmt(p: var TParser): PNode =
result = newNodeP(nkCommentStmt, p)
result.info.line = result.info.line - int16(1)
result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber)
type
TDefParser = proc (p: var TParser): PNode {.nimcall.}

0
compiler/pas2nim/nimrod.cfg Executable file → Normal file
View file

0
compiler/pas2nim/pas2nim.nim Executable file → Normal file
View file

0
compiler/pas2nim/paslex.nim Executable file → Normal file
View file

0
compiler/pas2nim/pasparse.nim Executable file → Normal file
View file

0
compiler/passaux.nim Executable file → Normal file
View file

0
compiler/passes.nim Executable file → Normal file
View file

0
compiler/pbraces.nim Executable file → Normal file
View file

0
compiler/pendx.nim Executable file → Normal file
View file

8
compiler/platform.nim Executable file → Normal file
View file

@ -21,7 +21,7 @@ type
# conditionals to condsyms (end of module).
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
osAtari, osNetware, osMacos, osMacosx, osHaiku, osEcmaScript, osNimrodVM,
osAtari, osNetware, osMacos, osMacosx, osHaiku, osJS, osNimrodVM,
osStandalone
type
@ -136,7 +136,7 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "EcmaScript", parDir: "..",
(name: "JS", parDir: "..",
dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A",
pathSep: ":", dirSep: "/",
@ -155,7 +155,7 @@ type
# alias conditionals to condsyms (end of module).
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
cpuEcmaScript, cpuNimrodVM, cpuAVR
cpuJS, cpuNimrodVM, cpuAVR
type
TEndian* = enum
@ -177,7 +177,7 @@ const
(name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "ecmascript", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
(name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]

7
compiler/pragmas.nim Executable file → Normal file
View file

@ -202,6 +202,8 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
result = newLib(kind)
result.path = path
Append(c.libs, result)
if path.kind in {nkStrLit..nkTripleStrLit}:
result.isOverriden = options.isDynLibOverride(path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
@ -225,8 +227,9 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
else:
if n.kind == nkExprColonExpr:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
addToLib(lib, sym)
incl(sym.loc.flags, lfDynamicLib)
if not lib.isOverriden:
addToLib(lib, sym)
incl(sym.loc.flags, lfDynamicLib)
else:
incl(sym.loc.flags, lfExportLib)
# since we'll be loading the dynlib symbols dynamically, we must use

59
compiler/procfind.nim Executable file → Normal file
View file

@ -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.
@ -10,28 +10,24 @@
# This module implements the searching for procs and iterators.
# This is needed for proper handling of forward declarations.
import
import
ast, astalgo, msgs, semdata, types, trees
proc equalGenericParams(procA, procB: PNode): bool =
var a, b: PSym
result = procA == procB
if result: return
if (procA == nil) or (procB == nil): return
if sonsLen(procA) != sonsLen(procB): return
for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym:
proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return
for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym:
InternalError(procA.info, "equalGenericParams")
return
if procB.sons[i].kind != nkSym:
if procB.sons[i].kind != nkSym:
InternalError(procB.info, "equalGenericParams")
return
a = procA.sons[i].sym
b = procB.sons[i].sym
if (a.name.id != b.name.id) or
let a = procA.sons[i].sym
let b = procB.sons[i].sym
if a.name.id != b.name.id or
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
if (a.ast != nil) and (b.ast != nil):
if not ExprStructuralEquivalent(a.ast, b.ast): return
if a.ast != nil and b.ast != nil:
if not ExprStructuralEquivalent(a.ast, b.ast): return
result = true
proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym =
@ -39,19 +35,32 @@ proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym =
# the same the sym in the symbol table is returned, else nil.
var it: TIdentIter
result = initIdentIter(it, c.tab.stack[tos], fn.Name)
while result != nil:
if (result.Kind == fn.kind):
if equalGenericParams(result.ast.sons[genericParamsPos],
fn.ast.sons[genericParamsPos]):
if isGenericRoutine(fn):
# we simply check the AST; this is imprecise but nearly the best what
# can be done; this doesn't work either though as type constraints are
# not kept in the AST ..
while result != nil:
if result.Kind == fn.kind and isGenericRoutine(result):
let genR = result.ast.sons[genericParamsPos]
let genF = fn.ast.sons[genericParamsPos]
if ExprStructuralEquivalent(genR, genF) and
ExprStructuralEquivalent(result.ast.sons[paramsPos],
fn.ast.sons[paramsPos]) and
equalGenericParams(genR, genF):
return
result = NextIdentIter(it, c.tab.stack[tos])
else:
while result != nil:
if result.Kind == fn.kind and not isGenericRoutine(result):
case equalParams(result.typ.n, fn.typ.n)
of paramsEqual:
return
of paramsIncompatible:
return
of paramsIncompatible:
LocalError(fn.info, errNotOverloadable, fn.name.s)
return
of paramsNotEqual:
return
of paramsNotEqual:
nil
result = NextIdentIter(it, c.tab.stack[tos])
result = NextIdentIter(it, c.tab.stack[tos])
when false:
proc paramsFitBorrow(child, parent: PNode): bool =

0
compiler/readme.txt Executable file → Normal file
View file

4
compiler/renderer.nim Executable file → Normal file
View file

@ -367,7 +367,7 @@ proc lsub(n: PNode): int =
else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n))
of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern:
of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
result = lsub(n.sons[0]) + lcomma(n, 1) + 2
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
@ -779,7 +779,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkRStrLit: put(g, tkRStrLit, atom(n))
of nkCharLit: put(g, tkCharLit, atom(n))
of nkNilLit: put(g, tkNil, atom(n)) # complex expressions
of nkCall, nkConv, nkDotCall, nkPattern:
of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
if sonsLen(n) >= 1: gsub(g, n.sons[0])
put(g, tkParLe, "(")
gcomma(g, n, 1)

323
compiler/rodread.nim Executable file → Normal file
View file

@ -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.
@ -127,7 +127,7 @@ type
options: TOptions
reason: TReasonForRecompile
modDeps: seq[int32]
files: TStringSeq
files: seq[int32]
dataIdx: int # offset of start of data section
convertersIdx: int # offset of start of converters section
initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
@ -140,6 +140,7 @@ type
memfile: TMemFile # unfortunately there is no point in time where we
# can close this! XXX
methods*: TSymSeq
inViewMode: bool
PRodReader* = ref TRodReader
@ -367,12 +368,12 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
inc(r.pos)
id = decodeVInt(r.s, r.pos)
setId(id)
else:
else:
InternalError(info, "decodeSym: no id")
if r.s[r.pos] == '&':
inc(r.pos)
ident = getIdent(decodeStr(r.s, r.pos))
else:
else:
InternalError(info, "decodeSym: no ident")
#echo "decoding: {", ident.s
result = PSym(IdTableGet(r.syms, id))
@ -381,8 +382,14 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
result.id = id
IdTablePut(r.syms, result, result)
if debugIds: registerID(result)
elif (result.id != id):
elif result.id != id:
InternalError(info, "decodeSym: wrong id")
elif result.kind != skStub and not r.inViewMode:
# we already loaded the symbol
return
else:
reset(result[])
result.id = id
result.kind = k
result.name = ident # read the rest of the symbol description:
if r.s[r.pos] == '^':
@ -495,7 +502,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
IdTablePut(r.syms, s, s)
StrTableAdd(rodCompilerProcs, s)
proc processIndex(r: PRodReader, idx: var TIndex) =
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
var key, val, tmp: int
inc(r.pos, 2) # skip "(\10"
inc(r.line)
@ -505,10 +512,11 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
inc(r.pos)
key = idx.lastIdxKey + tmp
val = decodeVInt(r.s, r.pos) + idx.lastIdxVal
else:
else:
key = idx.lastIdxKey + 1
val = tmp + idx.lastIdxVal
IITablePut(idx.tab, key, val)
if not outf.isNil: outf.write(key, " ", val, "\n")
idx.lastIdxKey = key
idx.lastIdxVal = val
setID(key) # ensure that this id will not be used
@ -523,7 +531,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
# new command forces us to consider it here :-)
case old
of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToEcmaScript, cmdCompileToLLVM:
cmdCompileToJS, cmdCompileToLLVM:
if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
cmdInteractive}:
return false
@ -576,9 +584,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos, 2) # skip "(\10"
inc(r.line)
while r.s[r.pos] != ')':
var relativePath = decodeStr(r.s, r.pos)
var resolvedPath = relativePath.findModule
r.files.add(if resolvedPath.len > 0: resolvedPath else: relativePath)
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
inc(r.pos) # skip #10
inc(r.line)
if r.s[r.pos] == ')': inc(r.pos)
@ -586,7 +595,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos, 2) # skip "(\10"
inc(r.line)
while r.s[r.pos] != ')':
w = r.files[decodeVInt(r.s, r.pos)]
w = r.files[decodeVInt(r.s, r.pos)].toFullPath
inc(r.pos) # skip ' '
inclCrc = decodeVInt(r.s, r.pos)
if r.reason == rrNone:
@ -598,8 +607,8 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
if r.s[r.pos] == ')': inc(r.pos)
of "DEPS":
inc(r.pos) # skip ':'
while r.s[r.pos] > '\x0A':
r.modDeps.add int32(decodeVInt(r.s, r.pos))
while r.s[r.pos] > '\x0A':
r.modDeps.add(r.files[int32(decodeVInt(r.s, r.pos))])
if r.s[r.pos] == ' ': inc(r.pos)
of "INTERF":
r.interfIdx = r.pos + 2
@ -670,11 +679,9 @@ proc newRodReader(modfilename: string, crc: TCrc32,
add(version, r.s[r.pos])
inc(r.pos)
if r.s[r.pos] == '\x0A': inc(r.pos)
if version == RodFileVersion:
if version != RodFileVersion:
# since ROD files are only for caching, no backwards compatibility is
# needed
processRodFile(r, crc)
else:
result = nil
else:
result = nil
@ -719,8 +726,14 @@ proc findSomeWhere(id: int) =
echo "found id ", id, " in ", gMods[i].filename
proc getReader(moduleId: int): PRodReader =
InternalAssert moduleId >= 0 and moduleId < gMods.len
result = gMods[moduleId].rd
# we can't index 'gMods' here as it's indexed by a *file index* which is not
# the module ID! We could introduce a mapping ID->PRodReader but I'll leave
# this for later versions if benchmarking shows the linear search causes
# problems:
for i in 0 .. <gMods.len:
result = gMods[i].rd
if result != nil and result.moduleId == moduleId: return result
return nil
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
result = PSym(IdTableGet(r.syms, id))
@ -810,6 +823,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else:
processRodFile(r, crc)
result = r.reason
if result == rrNone:
# check modules it depends on
@ -818,10 +832,10 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
# this, since results are cached.
var res = checkDep(SystemFileIdx)
if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)):
for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i])
if res != rrNone:
result = rrModDeps
if res != rrNone:
result = rrModDeps
# we cannot break here, because of side-effects of `checkDep`
if result != rrNone and gVerbosity > 0:
rawMessage(hintProcessing, reasonToFrmt[result] % filename)
@ -859,7 +873,9 @@ proc rawLoadStub(s: PSym) =
var d = IITableGet(rd.index.tab, s.id)
if d == invalidKey: InternalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, UnknownLineInfo())
if rs != s:
if rs != s:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
InternalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId:
InternalError(rs.info, "loadStub: wrong ID")
@ -894,3 +910,264 @@ proc getBody*(s: PSym): PNode =
InitIdTable(gTypeTable)
InitStrTable(rodCompilerProcs)
# viewer:
proc writeNode(f: TFile; n: PNode) =
f.write("(")
if n != nil:
f.write($n.kind)
if n.typ != nil:
f.write('^')
f.write(n.typ.id)
case n.kind
of nkCharLit..nkInt64Lit:
if n.intVal != 0:
f.write('!')
f.write(n.intVal)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
f.write('!')
f.write($n.floatVal)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
f.write('!')
f.write(n.strVal.escape)
of nkIdent:
f.write('!')
f.write(n.ident.s)
of nkSym:
f.write('!')
f.write(n.sym.id)
else:
for i in countup(0, sonsLen(n) - 1):
writeNode(f, n.sons[i])
f.write(")")
proc writeSym(f: TFile; s: PSym) =
if s == nil:
f.write("{}\n")
return
f.write("{")
f.write($s.kind)
f.write('+')
f.write(s.id)
f.write('&')
f.write(s.name.s)
if s.typ != nil:
f.write('^')
f.write(s.typ.id)
if s.owner != nil:
f.write('*')
f.write(s.owner.id)
if s.flags != {}:
f.write('$')
f.write($s.flags)
if s.magic != mNone:
f.write('@')
f.write($s.magic)
if s.options != gOptions:
f.write('!')
f.write($s.options)
if s.position != 0:
f.write('%')
f.write($s.position)
if s.offset != -1:
f.write('`')
f.write($s.offset)
if s.constraint != nil:
f.write('#')
f.writeNode(s.constraint)
if s.ast != nil:
f.writeNode(s.ast)
f.write("}\n")
proc writeType(f: TFile; t: PType) =
if t == nil:
f.write("[]\n")
return
f.write('[')
f.write($t.kind)
f.write('+')
f.write($t.id)
if t.n != nil:
f.writeNode(t.n)
if t.flags != {}:
f.write('$')
f.write($t.flags)
if t.callConv != low(t.callConv):
f.write('?')
f.write($t.callConv)
if t.owner != nil:
f.write('*')
f.write($t.owner.id)
if t.sym != nil:
f.write('&')
f.write(t.sym.id)
if t.size != -1:
f.write('/')
f.write($t.size)
if t.align != 2:
f.write('=')
f.write($t.align)
if t.containerID != 0:
f.write('@')
f.write($t.containerID)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
f.write("^()")
else:
f.write('^')
f.write($t.sons[i].id)
f.write("]\n")
proc viewFile(rodfile: string) =
var r = newRodReader(rodfile, 0, 0)
if r == nil:
rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
rodfile)
return
r.inViewMode = true
var outf = system.open(rodfile.changeFileExt(".rod.txt"), fmWrite)
while r.s[r.pos] != '\0':
let section = rdWord(r)
case section
of "CRC":
inc(r.pos) # skip ':'
outf.writeln("CRC:", $decodeVInt(r.s, r.pos))
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
outf.writeln("ID:", $r.moduleID)
of "OPTIONS":
inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
outf.writeln("OPTIONS:", $r.options)
of "GOPTIONS":
inc(r.pos) # skip ':'
let dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
outf.writeln("GOPTIONS:", $dep)
of "CMD":
inc(r.pos) # skip ':'
let dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
outf.writeln("CMD:", $dep)
of "DEFINES":
inc(r.pos) # skip ':'
var d = 0
outf.write("DEFINES:")
while r.s[r.pos] > '\x0A':
let w = decodeStr(r.s, r.pos)
inc(d)
outf.write(" ", w)
if r.s[r.pos] == ' ': inc(r.pos)
outf.write("\n")
of "FILES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
outf.write("FILES(\n")
while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
inc(r.pos) # skip #10
inc(r.line)
outf.writeln finalPath
if r.s[r.pos] == ')': inc(r.pos)
outf.write(")\n")
of "INCLUDES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
outf.write("INCLUDES(\n")
while r.s[r.pos] != ')':
let w = r.files[decodeVInt(r.s, r.pos)]
inc(r.pos) # skip ' '
let inclCrc = decodeVInt(r.s, r.pos)
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
outf.write(w, " ", inclCrc, "\n")
if r.s[r.pos] == ')': inc(r.pos)
outf.write(")\n")
of "DEPS":
inc(r.pos) # skip ':'
outf.write("DEPS:")
while r.s[r.pos] > '\x0A':
let v = int32(decodeVInt(r.s, r.pos))
r.modDeps.add(r.files[v])
if r.s[r.pos] == ' ': inc(r.pos)
outf.write(" ", r.files[v])
outf.write("\n")
of "INTERF", "COMPILERPROCS":
inc r.pos, 2
if section == "INTERF": r.interfIdx = r.pos
else: r.compilerProcsIdx = r.pos
outf.write(section, "(\n")
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
let w = decodeStr(r.s, r.pos)
inc(r.pos)
let key = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
outf.write(w, " ", key, "\n")
if r.s[r.pos] == ')': inc r.pos
outf.write(")\n")
of "INDEX":
outf.write(section, "(\n")
processIndex(r, r.index, outf)
outf.write(")\n")
of "IMPORTS":
outf.write(section, "(\n")
processIndex(r, r.imports, outf)
outf.write(")\n")
of "CONVERTERS", "METHODS":
inc r.pos
if section == "METHODS": r.methodsIdx = r.pos
else: r.convertersIdx = r.pos
outf.write(section, ":")
while r.s[r.pos] > '\x0A':
let d = decodeVInt(r.s, r.pos)
outf.write(" ", $d)
if r.s[r.pos] == ' ': inc(r.pos)
outf.write("\n")
of "DATA":
inc(r.pos, 2)
r.dataIdx = r.pos
outf.write("DATA(\n")
while r.s[r.pos] != ')':
if r.s[r.pos] == '(':
outf.writeNode decodeNode(r, UnknownLineInfo())
outf.write("\n")
elif r.s[r.pos] == '[':
outf.writeType decodeType(r, UnknownLineInfo())
else:
outf.writeSym decodeSym(r, UnknownLineInfo())
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
if r.s[r.pos] == ')': inc r.pos
outf.write(")\n")
of "INIT":
outf.write("INIT(\n")
inc r.pos, 2
r.initIdx = r.pos
while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')':
let d = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
#let p = r.pos
#r.pos = d + r.dataIdx
#outf.writeNode decodeNode(r, UnknownLineInfo())
#outf.write("\n")
#r.pos = p
if r.s[r.pos] == ')': inc r.pos
outf.write("<not supported by viewer>)\n")
else:
InternalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
skipSection(r)
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
outf.close
when isMainModule:
viewFile(paramStr(1).addFileExt(rodExt))

0
compiler/rodutils.nim Executable file → Normal file
View file

3
compiler/rodwrite.nim Executable file → Normal file
View file

@ -205,6 +205,9 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: InternalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)
add(result, '+')
encodeVInt(t.id, result)

0
compiler/ropes.nim Executable file → Normal file
View file

18
compiler/sem.nim Executable file → Normal file
View file

@ -19,19 +19,15 @@ import
# implementation
type
TExprFlag = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
procvar.}
proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
proc changeType(n: PNode, newType: PType)
proc changeType(n: PNode, newType: PType, check: bool)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
@ -200,14 +196,12 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
result = semExpr(c, n, {})
proc myOpen(module: PSym): PPassContext =
var c = newContext(module)
if c.p != nil: InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExprNoFlags
c.semExpr = semExpr
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall
c.semTypeNode = semTypeNode

9
compiler/semcall.nim Executable file → Normal file
View file

@ -85,7 +85,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
#writeMatches(alt)
if c.inCompilesContext > 0:
# quick error message for performance of 'compiles' built-in:
GlobalError(n.Info, errAmbiguousCallXYZ, "")
GlobalError(n.Info, errGenerated, "ambiguous call")
elif gErrorCounter == 0:
# don't cascade errors
var args = "("
@ -174,7 +174,10 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# common case; check the only candidate has the right
# number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
return explicitGenericInstError(n)
let expected = safeLen(s.ast.sons[genericParamsPos])
LocalError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
@ -204,7 +207,7 @@ proc SearchForBorrowProc(c: PContext, fn: PSym, tos: int): PSym =
call.add(newIdentNode(fn.name, fn.info))
for i in 1.. <fn.typ.n.len:
let param = fn.typ.n.sons[i]
let t = skipTypes(param.typ, abstractVar)
let t = skipTypes(param.typ, abstractVar-{tyTypeDesc})
call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
var resolved = semOverloadedCall(c, call, call, {fn.kind})
if resolved != nil:

8
compiler/semdata.nim Executable file → Normal file
View file

@ -39,6 +39,11 @@ type
TInstantiationPair* = object
genericSym*: PSym
inst*: PInstantiation
TExprFlag* = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
efAllowDestructor
TExprFlags* = set[TExprFlag]
PContext* = ref TContext
TContext* = object of TPassContext # a context represents a module
@ -64,7 +69,8 @@ type
# to some new symbol in a generic instantiation
libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.}

277
compiler/semexprs.nim Executable file → Normal file
View file

@ -10,18 +10,6 @@
# this module does the semantic checking for expressions
# included from sem.nim
proc restoreOldStyleType(n: PNode) =
# XXX: semExprWithType used to return the same type
# for nodes such as (100) or (int).
# This is inappropriate. The type of the first expression
# should be "int", while the type of the second one should
# be typedesc(int).
#
# This is strictly for backward compatibility until
# the transition to types as first-class values is complete.
if n.typ.kind == tyTypeDesc and n.typ.sonsLen == 1:
n.typ = n.typ.sons[0]
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s)
pushInfoContext(n.info)
@ -31,32 +19,67 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc newDeref(n: PNode): PNode {.inline.} =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
addSon(result, n)
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
smoduleId != c.module.id and smoduleId != c.friendModule.id:
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semProcvarCheck(c: PContext, n: PNode) =
let n = n.skipConv
if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skIterator,
skConverter}:
performProcvarCheck(c, n, n.sym)
proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}:
if instantiateDestructor(c, n.typ):
LocalError(n.info, errGenerated,
"usage of a type with a destructor in a non destructible context")
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags)
if result.kind == nkEmpty:
# do not produce another redundant error message:
#raiseRecoverableError("")
result = errorNode(c, n)
if result.typ != nil:
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyVar: result = newDeref(result)
else:
LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags)
if result.kind == nkEmpty:
# do not produce another redundant error message:
#raiseRecoverableError("")
result = errorNode(c, n)
if result.typ != nil:
# XXX tyGenericInst here?
semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result)
semDestructorCheck(c, result, flags)
else:
LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags)
if result.kind == nkEmpty:
# do not produce another redundant error message:
result = errorNode(c, n)
if result.typ == nil:
LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
else:
semProcvarCheck(c, result)
semDestructorCheck(c, result, flags)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed)
@ -65,21 +88,12 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast)
result.typ = s.typ
result.info = n.info
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
# XXX this not correct; it's valid to pass to templates and macros.
# We really need another post nkCallConv check for this. Or maybe do it
# in transform().
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
smoduleId != c.module.id and smoduleId != c.friendModule.id:
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind
of skConst:
markUsed(n, s)
case skipTypes(s.typ, abstractInst).kind
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64:
result = inlineConst(n, s)
@ -149,7 +163,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
result = convNotNeedeed
return
var d = skipTypes(castDest, abstractVar)
var s = skipTypes(src, abstractVar)
var s = skipTypes(src, abstractVar-{tyTypeDesc})
while (d != nil) and (d.Kind in {tyPtr, tyRef}) and (d.Kind == s.Kind):
d = base(d)
s = base(s)
@ -158,7 +172,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
elif d.Kind == tyObject and s.Kind == tyObject:
result = checkConversionBetweenObjects(d, s)
elif (skipTypes(castDest, abstractVarRange).Kind in IntegralTypes) and
(skipTypes(src, abstractVarRange).Kind in IntegralTypes):
(skipTypes(src, abstractVarRange-{tyTypeDesc}).Kind in IntegralTypes):
# accept conversion between integral types
else:
# we use d, s here to speed up that operation a bit:
@ -185,7 +199,7 @@ proc isCastable(dst, src: PType): bool =
else:
result = (ds >= ss) or
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst).kind in IntegralTypes)
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
@ -199,7 +213,7 @@ proc semConv(c: PContext, n: PNode, s: PSym): PNode =
addSon(result, copyTree(n.sons[0]))
addSon(result, semExprWithType(c, n.sons[1]))
var op = result.sons[1]
if not isSymChoice(op):
let status = checkConvertible(result.typ, op.typ)
case status
@ -238,24 +252,24 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
LocalError(n.info, errXExpectsTypeOrValue, opToStr[m])
else:
n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
var typ = skipTypes(n.sons[1].typ, abstractVarRange)
case typ.Kind
of tySequence, tyString, tyOpenArray, tyVarargs:
n.typ = getSysType(tyInt)
of tyArrayConstr, tyArray:
n.typ = n.sons[1].typ.sons[0] # indextype
n.typ = typ.sons[0] # indextype
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
n.typ = n.sons[1].typ
# do not skip the range!
n.typ = n.sons[1].typ.skipTypes(abstractVar)
else: LocalError(n.info, errInvalidArgForX, opToStr[m])
result = n
proc semSizeof(c: PContext, n: PNode): PNode =
proc semSizeof(c: PContext, n: PNode): PNode =
if sonsLen(n) != 2:
LocalError(n.info, errXExpectsTypeOrValue, "sizeof")
else:
else:
n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
#restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt)
result = n
@ -265,10 +279,10 @@ proc semOf(c: PContext, n: PNode): PNode =
n.sons[2] = semExprWithType(c, n.sons[2])
#restoreOldStyleType(n.sons[1])
#restoreOldStyleType(n.sons[2])
let a = skipTypes(n.sons[1].typ, typedescPtrs)
let b = skipTypes(n.sons[2].typ, typedescPtrs)
let x = skipTypes(n.sons[1].typ, abstractPtrs)
let y = skipTypes(n.sons[2].typ, abstractPtrs)
let a = skipTypes(n.sons[1].typ, abstractPtrs)
let b = skipTypes(n.sons[2].typ, abstractPtrs)
let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
LocalError(n.info, errXExpectsObjectTypes, "of")
@ -319,7 +333,7 @@ proc semIs(c: PContext, n: PNode): PNode =
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}
for i in countup(1, n.sonsLen- 1):
for i in countup(1, n.sonsLen-1):
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info
@ -328,7 +342,7 @@ proc semOpAux(c: PContext, n: PNode) =
a.typ = a.sons[1].typ
else:
n.sons[i] = semExprWithType(c, a, flags)
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
var par = getIdent("()")
@ -340,11 +354,11 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
result = semExpr(c, result)
proc changeType(n: PNode, newType: PType) =
proc changeType(n: PNode, newType: PType, check: bool) =
case n.kind
of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType))
changeType(n.sons[i], elemType(newType), check)
of nkPar:
if newType.kind != tyTuple:
InternalError(n.info, "changeType: no tuple type for constructor")
@ -359,15 +373,21 @@ proc changeType(n: PNode, newType: PType) =
if f == nil:
internalError(m.info, "changeType(): invalid identifier")
return
changeType(n.sons[i].sons[1], f.typ)
changeType(n.sons[i].sons[1], f.typ, check)
else:
for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m)
changeType(m, newType.sons[i])
changeType(m, newType.sons[i], check)
n.sons[i] = a
of nkCharLit..nkUInt64Lit:
if check:
let value = n.intVal
if value < firstOrd(newType) or value > lastOrd(newType):
LocalError(n.info, errGenerated, "cannot convert " & $value &
" to " & typeToString(newType))
else: nil
n.typ = newType
@ -384,13 +404,13 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
result = typ
proc semArrayConstr(c: PContext, n: PNode): PNode =
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArrayConstr, c)
rawAddSon(result.typ, nil) # index type
if sonsLen(n) == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
else:
else:
var x = n.sons[0]
var lastIndex: biggestInt = 0
var indexType = getSysType(tyInt)
@ -413,7 +433,7 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
localError(x.info, errInvalidOrderInArrayConstructor)
x = x.sons[1]
n.sons[i] = semExprWithType(c, x)
n.sons[i] = semExprWithType(c, x, flags*{efAllowDestructor})
addSon(result, fitNode(c, typ, n.sons[i]))
inc(lastIndex)
addSonSkipIntLit(result.typ, typ)
@ -447,11 +467,11 @@ proc fixAbstractType(c: PContext, n: PNode) =
elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar)
changeType(it.sons[1], s)
changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1]
of nkBracket:
# an implicitely constructed array (passed to an open array):
n.sons[i] = semArrayConstr(c, it)
n.sons[i] = semArrayConstr(c, it, {})
else:
nil
#if (it.typ == nil):
@ -483,9 +503,10 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
result = n
case n.kind
of nkSym:
of nkSym:
# n.sym.typ can be nil in 'check' mode ...
if n.sym.typ != nil and skipTypes(n.sym.typ, abstractInst).kind != tyVar:
if n.sym.typ != nil and
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
incl(n.sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n)
of nkDotExpr:
@ -493,16 +514,16 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
if n.sons[1].kind != nkSym:
internalError(n.info, "analyseIfAddressTaken")
return
if skipTypes(n.sons[1].sym.typ, abstractInst).kind != tyVar:
if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
incl(n.sons[1].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n)
of nkBracketExpr:
checkMinSonsLen(n, 1)
if skipTypes(n.sons[0].typ, abstractInst).kind != tyVar:
if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar:
if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n)
else:
result = newHiddenAddrTaken(c, n) # BUGFIX!
result = newHiddenAddrTaken(c, n)
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
checkMinSonsLen(n, 1)
@ -517,16 +538,24 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
# BUGFIX: check for L-Value still needs to be done for the arguments!
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
for i in countup(1, sonsLen(n) - 1):
if i < sonsLen(t) and t.sons[i] != nil and
skipTypes(t.sons[i], abstractInst).kind == tyVar:
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}:
LocalError(n.sons[i].info, errVarForOutParamNeeded)
if n.sons[i].kind != nkHiddenAddr:
LocalError(n.sons[i].info, errVarForOutParamNeeded)
return
for i in countup(1, sonsLen(n) - 1):
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkHiddenCallConv:
# we need to recurse explicitly here as converters can create nested
# calls and then they wouldn't be analysed otherwise
analyseIfAddressTakenInCall(c, n.sons[i])
semProcvarCheck(c, n.sons[i])
if i < sonsLen(t) and
skipTypes(t.sons[i], abstractInst).kind == tyVar:
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
if n.sons[i].kind != nkHiddenAddr:
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
include semmagic
@ -541,11 +570,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
call.add(n.sons[0])
var allConst = true
for i in 1 .. < n.len:
let a = getConstExpr(c.module, n.sons[i])
if a != nil: call.add(a)
else:
var a = getConstExpr(c.module, n.sons[i])
if a == nil:
allConst = false
call.add(n.sons[i])
a = n.sons[i]
if a.kind == nkHiddenStdConv: a = a.sons[1]
call.add(a)
if allConst:
result = semfold.getConstExpr(c.module, call)
if result.isNil: result = n
@ -617,6 +647,7 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
checkMinSonsLen(n, 1)
@ -635,8 +666,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst)
if (t != nil) and (t.kind == tyProc):
if n.sons[0].typ != nil:
t = skipTypes(n.sons[0].typ, abstractInst-{tyTypedesc})
if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution
var m: TCandidate
initCandidate(m, t)
@ -668,10 +700,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we assume that a procedure that calls something indirectly
# has side-effects:
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
elif (t != nil) and t.kind == tyTypeDesc:
elif t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags)
let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
result = semConv(c, n, symFromType(destType, n.info))
return
return
else:
result = overloadedCallOpr(c, n)
# Now that nkSym does not imply an iteration over the proc/iterator space,
@ -694,7 +727,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
semOpAux(c, n)
#semLazyOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
result = overloadedCallOpr(c, n)
@ -706,6 +739,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, result, callee)
else:
semFinishOperands(c, n)
activate(c, n)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@ -714,7 +748,8 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = evalAtCompileTime(c, result)
proc buildStringify(c: PContext, arg: PNode): PNode =
if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString:
if arg.typ != nil and
skipTypes(arg.typ, abstractInst-{tyTypeDesc}).kind == tyString:
result = arg
else:
result = newNodeI(nkCall, arg.info)
@ -752,7 +787,7 @@ proc discardCheck(result: PNode) =
# XXX too much work and fixing would break bootstrapping:
#Message(n.info, warnNilStatement)
result.typ = nil
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError and
elif not ImplicitlyDiscardable(result) and result.typ.kind != tyError and
gCmd != cmdInteractive:
localError(result.info, errDiscardValue)
@ -845,16 +880,17 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semSym(c, n, s, flags)
n.sons[0] = semExprWithType(c, n.sons[0], flags)
restoreOldStyleType(n.sons[0])
#restoreOldStyleType(n.sons[0])
var i = considerAcc(n.sons[1])
var ty = n.sons[0].typ
var f: PSym = nil
result = nil
if isTypeExpr(n.sons[0]):
if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.len == 1:
if ty.kind == tyTypeDesc: ty = ty.sons[0]
case ty.kind
of tyEnum:
of tyEnum:
# look up if the identifier belongs to the enum:
while ty != nil:
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty.sons[0] # enum inheritance
@ -881,7 +917,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX: This is probably not relevant any more
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
ty = n.sons[0].Typ
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
var check: PNode = nil
if ty.kind == tyObject:
@ -971,7 +1007,8 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0])
for i in countup(1, sonsLen(n) - 1):
n.sons[i] = semExprWithType(c, n.sons[i], flags)
n.sons[i] = semExprWithType(c, n.sons[i],
flags*{efInTypeof, efDetermineType})
var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
if arg != nil:
@ -1082,11 +1119,13 @@ proc semAsgn(c: PContext, n: PNode): PNode =
localError(a.info, errXCannotBeAssignedTo,
renderTree(a, {renderNoComments}))
else:
var
rhs = semExprWithType(c, n.sons[1])
let
lhs = n.sons[0]
if lhs.kind == nkSym and lhs.sym.kind == skResult and
lhs.sym.typ.kind == tyGenericParam:
lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
var
rhs = semExprWithType(c, n.sons[1],
if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult and lhs.sym.typ.kind == tyGenericParam:
if matchTypeClass(lhs.typ, rhs.typ):
InternalAssert c.p.resultSym != nil
lhs.typ = rhs.typ
@ -1128,7 +1167,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
# ``result``:
if result.kind == nkSym and result.sym == c.p.resultSym:
nil
elif result.kind == nkNilLit or ImplicitelyDiscardable(result):
elif result.kind == nkNilLit or ImplicitlyDiscardable(result):
# intended semantic: if it's 'discardable' and the context allows for it,
# discard it. This is bad for chaining but nicer for C wrappers.
# ambiguous :-(
@ -1531,21 +1570,22 @@ proc checkPar(n: PNode): TParKind =
LocalError(n.sons[i].info, errNamedExprNotAllowed)
return paNone
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newNodeI(nkPar, n.info)
var typ = newTypeS(tyTuple, c)
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
var ids = initIntSet()
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
if (n.sons[i].kind != nkExprColonExpr) or
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
illFormedAst(n.sons[i])
var id: PIdent
if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
else: id = n.sons[i].sons[0].sym.name
if ContainsOrIncl(ids, id.id):
localError(n.sons[i].info, errFieldInitTwice, id.s)
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
flags*{efAllowDestructor})
var f = newSymS(skField, n.sons[i].sons[0], c)
f.typ = skipIntLit(n.sons[i].sons[1].typ)
rawAddSon(typ, f.typ)
@ -1554,14 +1594,56 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
addSon(result, n.sons[i])
result.typ = typ
proc semTuplePositionsConstr(c: PContext, n: PNode): PNode =
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = n # we don't modify n, but compute the type:
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
for i in countup(0, sonsLen(n) - 1):
n.sons[i] = semExprWithType(c, n.sons[i])
n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
addSonSkipIntLit(typ, n.sons[i].typ)
result.typ = typ
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
var t = semTypeNode(c, n.sons[0], nil)
result = n
result.typ = t
result.kind = nkObjConstr
t = skipTypes(t, abstractInst)
if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
if t.kind != tyObject:
localError(n.info, errGenerated, "object constructor needs an object type")
return
var ids = initIntSet()
for i in 1.. <n.len:
let it = n.sons[i]
if it.kind != nkExprColonExpr or it.sons[0].kind notin {nkSym, nkIdent}:
localError(n.info, errNamedExprExpected)
break
var id: PIdent
if it.sons[0].kind == nkIdent: id = it.sons[0].ident
else: id = it.sons[0].sym.name
if ContainsOrIncl(ids, id.id):
localError(it.info, errFieldInitTwice, id.s)
var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
var
check: PNode = nil
f: PSym
while true:
check = nil
f = lookupInRecordAndBuildCheck(c, it, t.n, id, check)
if f != nil: break
if t.sons[0] == nil: break
t = skipTypes(t.sons[0], {tyGenericInst})
if f != nil and fieldVisible(c, f):
it.sons[0] = newSymNode(f)
e = fitNode(c, f.typ, e)
# small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
# 3 childen the last being the field check
if check != nil: it.add(check)
else:
localError(it.info, errUndeclaredFieldX, id.s)
it.sons[1] = e
# XXX object field name check for 'case objects' if the kind is static?
proc semStmtListExpr(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 1)
@ -1655,7 +1737,7 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out
# the planned overload resolution reforms
for i in 1 .. <n.len:
for i in 1 .. <safeLen(n):
if n[i].kind == nkDo: n.sons[i] = n[i][bodyPos]
result = n
@ -1690,7 +1772,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skIterator, skConverter}:
performProcvarCheck(c, n, s)
#performProcvarCheck(c, n, s)
result = symChoice(c, n, s, scClosed)
if result.kind == nkSym:
markIndirect(c, result.sym)
@ -1769,6 +1851,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# XXX think about this more (``set`` procs)
if n.len == 2:
result = semConv(c, n, s)
elif n.len == 1:
result = semObjConstr(c, n, flags)
elif Contains(c.AmbiguousSymbols, s.id):
LocalError(n.info, errUseQualifier, s.name.s)
elif s.magic == mNone: result = semDirectOp(c, n, flags)
@ -1807,11 +1891,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkPar:
case checkPar(n)
of paNone: result = errorNode(c, n)
of paTuplePositions: result = semTuplePositionsConstr(c, n)
of paTupleFields: result = semTupleFieldsConstr(c, n)
of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(c, n, flags)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:

55
compiler/semfold.nim Executable file → Normal file
View file

@ -458,21 +458,28 @@ proc getAppType(n: PNode): PNode =
else:
result = newStrNodeT("console", n)
proc foldConv*(n, a: PNode): PNode =
proc rangeCheck(n: PNode, value: biggestInt) =
if value < firstOrd(n.typ) or value > lastOrd(n.typ):
LocalError(n.info, errGenerated, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode =
# XXX range checks?
case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64: result = newIntNodeT(system.toInt(getFloat(a)), n)
of tyFloat..tyFloat64:
result = newIntNodeT(system.toInt(getFloat(a)), n)
of tyChar: result = newIntNodeT(getOrdValue(a), n)
else:
result = a
result.typ = n.typ
of tyFloat..tyFloat64:
if check: rangeCheck(n, result.intVal)
of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
else:
else:
result = a
result.typ = n.typ
of tyOpenArray, tyVarargs, tyProc:
@ -490,7 +497,7 @@ proc getArrayConstr(m: PSym, n: PNode): PNode =
proc foldArrayAccess(m: PSym, n: PNode): PNode =
var x = getConstExpr(m, n.sons[0])
if x == nil: return
if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return
var y = getConstExpr(m, n.sons[1])
if y == nil: return
@ -516,13 +523,13 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
LocalError(n.info, errIndexOutOfBounds)
else: nil
proc foldFieldAccess(m: PSym, n: PNode): PNode =
proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0])
if x == nil or x.kind != nkPar: return
if x == nil or x.kind notin {nkObjConstr, nkPar}: return
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
@ -541,7 +548,12 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
let a = getConstExpr(m, n.sons[i])
if a == nil: return nil
result.strVal.add(getStrOrChar(a))
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
result = newSymNode(s, info)
result.typ = newType(tyTypeDesc, s.owner)
result.typ.addSonSkipIntLit(s.typ)
proc getConstExpr(m: PSym, n: PNode): PNode =
result = nil
case n.kind
@ -569,6 +581,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if sfFakeConst notin s.flags: result = copyTree(s.ast)
elif s.kind in {skProc, skMethod}: # BUGFIX
result = n
elif s.kind in {skType, skGenericParam}:
result = newSymNodeTypeDesc(s, n.info)
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:
@ -587,16 +601,18 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof")
result = nil
elif skipTypes(a.typ, abstractInst).kind in {tyArray,tyObject,tyTuple}:
elif skipTypes(a.typ, typedescInst).kind in
IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n)
else:
result = nil
# XXX: size computation for complex types is still wrong
else:
result = newIntNodeT(getSize(a.typ), n)
of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n)
of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tyOpenArray, tyVarargs, tySequence, tyString}:
{tyOpenArray, tyVarargs, tySequence, tyString}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
else:
var a = getArrayConstr(m, n.sons[1])
@ -647,7 +663,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if a == nil: return nil
result.sons[i] = a
incl(result.flags, nfAllConst)
of nkPar:
of nkObjConstr:
result = copyTree(n)
for i in countup(1, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i].sons[1])
if a == nil: return nil
result.sons[i].sons[1] = a
incl(result.flags, nfAllConst)
of nkPar:
# tuple constructor
result = copyTree(n)
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
@ -678,8 +701,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result.typ = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
var a = getConstExpr(m, n.sons[1])
if a == nil: return
result = foldConv(n, a)
if a == nil: return
result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
else:

12
compiler/semgnrc.nim Executable file → Normal file
View file

@ -30,7 +30,7 @@ proc getIdentNode(n: PNode): PNode =
else:
illFormedAst(n)
result = n
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
proc semGenericStmtScope(c: PContext, n: PNode,
@ -63,12 +63,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
result = newSymNode(s, n.info)
result = newSymNodeTypeDesc(s, n.info)
of skParam:
result = n
of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNode(s, n.info)
result = newSymNodeTypeDesc(s, n.info)
else:
result = n
else: result = newSymNode(s, n.info)
@ -156,13 +156,13 @@ proc semGenericStmt(c: PContext, n: PNode,
of skProc, skMethod, skIterator, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
first = 1
of skGenericParam:
result.sons[0] = newSymNode(s, n.sons[0].info)
of skGenericParam:
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
first = 1
of skType:
# bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result.sons[0] = newSymNode(s, n.sons[0].info)
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
first = 1
else:
result.sons[0] = newSymNode(s, n.sons[0].info)

0
compiler/seminst.nim Executable file → Normal file
View file

View file

@ -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.
@ -23,9 +23,10 @@ proc expectIntLit(c: PContext, n: PNode): int =
proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkPar, n.info, n.typ)
let idx = expectIntLit(c, n.sons[1])
let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
filename.strVal = ToFilename(info)
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.ToFilename
var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
line.intVal = ToLinenumber(info)
result.add(filename)
@ -73,6 +74,33 @@ proc semBindSym(c: PContext, n: PNode): PNode =
else:
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
proc semLocals(c: PContext, n: PNode): PNode =
var counter = 0
var tupleType = newTypeS(tyTuple, c)
result = newNodeIT(nkPar, n.info, tupleType)
tupleType.n = newNodeI(nkRecList, n.info)
# for now we skip openarrays ...
for i in countdown(c.tab.tos-1, ModuleTablePos+1):
for it in items(c.tab.stack[i]):
# XXX parameters' owners are wrong for generics; this caused some pain
# for closures too; we should finally fix it.
#if it.owner != c.p.owner: return result
if it.kind in skLocalVars and
it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
{tyVarargs, tyOpenArray, tyTypeDesc, tyExpr, tyStmt, tyEmpty}:
var field = newSym(skField, it.name, getCurrOwner(), n.info)
field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
field.position = counter
inc(counter)
addSon(tupleType.n, newSymNode(field))
addSonSkipIntLit(tupleType, field.typ)
var a = newSymNode(it, result.info)
if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
result.add(a)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode =
@ -86,5 +114,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mOrd: result = semOrd(c, n)
of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n)
else: result = n

View file

@ -14,9 +14,7 @@ import
# Second semantic checking pass over the AST. Necessary because the old
# way had some inherent problems. Performs:
#
# * procvar checks
# * effect+exception tracking
# * closure analysis
# * checks for invalid usages of compiletime magics (not implemented)
# * checks for invalid usages of PNimNode (not implemented)
# * later: will do an escape analysis for closures at least

178
compiler/semstmts.nim Executable file → Normal file
View file

@ -119,11 +119,11 @@ proc semWhile(c: PContext, n: PNode): PNode =
closeScope(c.tab)
proc toCover(t: PType): biggestInt =
var t2 = skipTypes(t, abstractVarRange)
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n)
else:
result = lengthOrd(skipTypes(t, abstractVar))
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
proc semCase(c: PContext, n: PNode): PNode =
# check selector:
@ -133,7 +133,7 @@ proc semCase(c: PContext, n: PNode): PNode =
n.sons[0] = semExprWithType(c, n.sons[0])
var chckCovered = false
var covered: biggestint = 0
case skipTypes(n.sons[0].Typ, abstractVarRange).Kind
case skipTypes(n.sons[0].Typ, abstractVarRange-{tyTypeDesc}).Kind
of tyInt..tyInt64, tyChar, tyEnum:
chckCovered = true
of tyFloat..tyFloat128, tyString, tyError:
@ -166,10 +166,10 @@ proc semCase(c: PContext, n: PNode): PNode =
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ)
changeType(result.sons[1], typ, check=true)
result = result.sons[1]
elif not sameType(result.typ, typ):
changeType(result, typ)
elif not sameType(result.typ, typ):
changeType(result, typ, check=false)
proc findShadowedVar(c: PContext, v: PSym): PSym =
for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
@ -203,11 +203,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var typ: PType
if a.sons[length-2].kind != nkEmpty:
typ = semTypeNode(c, a.sons[length-2], nil)
else:
else:
typ = nil
var def: PNode
if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1])
if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
# BUGFIX: ``fitNode`` is needed here!
# check type compability between def.typ and typ:
if typ != nil: def = fitNode(c, typ, def)
@ -301,52 +301,109 @@ proc semConst(c: PContext, n: PNode): PNode =
addSon(b, copyTree(def))
addSon(result, b)
proc transfFieldLoopBody(n: PNode, forLoop: PNode,
tupleType: PType,
tupleIndex, first: int): PNode =
type
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
tupleType: PType # if != nil we're traversing a tuple
tupleIndex: int
field: PSym
replaceByFieldName: bool
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent:
result = n
var L = sonsLen(forLoop)
# field name:
if first > 0:
if c.replaceByFieldName:
if n.ident.id == forLoop[0].ident.id:
if tupleType.n == nil:
# ugh, there are no field names:
result = newStrNode(nkStrLit, "")
else:
result = newStrNode(nkStrLit, tupleType.n.sons[tupleIndex].sym.name.s)
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
result = newStrNode(nkStrLit, fieldName)
return
# other fields:
for i in first..L-3:
for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-first]
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, tupleIndex))
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, c.tupleIndex))
else:
result = newNodeI(nkDotExpr, n.info)
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1):
result.sons[i] = transfFieldLoopBody(n.sons[i], forLoop,
tupleType, tupleIndex, first)
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
type
TFieldsCtx = object
c: PContext
m: TMagic
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
case typ.kind
of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c.tab)
inc c.c.InUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(SemStmt(c.c, body))
dec c.c.InUnrolledContext
closeScope(c.c.tab)
of nkNilLit: nil
of nkRecCase:
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
LocalError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
semForObjectFields(c, typ[0], forLoop, father)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
# generate selector:
var access = newNodeI(nkDotExpr, forLoop.info, 2)
access.sons[0] = call.sons[1]
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
caseStmt.add(semExprWithType(c.c, access))
# copy the branches over, but replace the fields with the for loop body:
for i in 1 .. <typ.len:
var branch = copyTree(typ[i])
let L = branch.len
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
caseStmt.add(branch)
father.add(caseStmt)
of nkRecList:
for t in items(typ): semForObjectFields(c, t, forLoop, father)
else:
illFormedAst(typ)
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info)
result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
if trueSymbol == nil:
LocalError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool)
result.add(newSymNode(trueSymbol, n.info))
result.sons[0] = newSymNode(trueSymbol, n.info)
var stmts = newNodeI(nkStmtList, n.info)
result.add(stmts)
result.sons[1] = stmts
var length = sonsLen(n)
var call = n.sons[length-2]
@ -354,23 +411,34 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
LocalError(n.info, errWrongNumberOfVariables)
return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar)
if tupleTypeA.kind != tyTuple: InternalError(n.info, "no tuple type!")
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1:
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar)
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
if not SameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
Inc(c.p.nestedLoopCounter)
var loopBody = n.sons[length-1]
for i in 0..sonsLen(tupleTypeA)-1:
openScope(c.tab)
var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i,
ord(m==mFieldPairs))
inc c.InUnrolledContext
stmts.add(SemStmt(c, body))
dec c.InUnrolledContext
closeScope(c.tab)
if tupleTypeA.kind == tyTuple:
var loopBody = n.sons[length-1]
for i in 0..sonsLen(tupleTypeA)-1:
openScope(c.tab)
var fc: TFieldInstCtx
fc.tupleType = tupleTypeA
fc.tupleIndex = i
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.InUnrolledContext
stmts.add(SemStmt(c, body))
dec c.InUnrolledContext
closeScope(c.tab)
else:
var fc: TFieldsCtx
fc.m = m
fc.c = c
semForObjectFields(fc, tupleTypeA.n, n, stmts)
Dec(c.p.nestedLoopCounter)
var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode)
@ -416,10 +484,17 @@ proc semForVars(c: PContext, n: PNode): PNode =
n.sons[length-1] = SemStmt(c, n.sons[length-1])
Dec(c.p.nestedLoopCounter)
proc newDeref(n: PNode): PNode {.inline.} =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
addSon(result, n)
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
result = newNodeI(nkCall, arg.info)
result.add(newIdentNode(it.getIdent, arg.info))
result.add(arg)
if arg.typ != nil and arg.typ.kind == tyVar:
result.add newDeref(arg)
else:
result.add arg
result = semExprNoDeref(c, result, {efWantIterator})
proc semFor(c: PContext, n: PNode): PNode =
@ -705,8 +780,7 @@ proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned.
when false:
# well for now it breaks code ... I added the test case in main.nim of the
# compiler itself to break bootstrapping :P
# well for now it breaks code ...
case n.kind
of nkLambdaKinds:
discard semLambda(c, n, {})
@ -994,7 +1068,7 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
result = nil
proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object ot tuple type
## generate a destructor for a user-defined object or tuple type
## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt =
@ -1029,7 +1103,7 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
if t.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is alrady defined" problem
# it temporarily to hide the "destroy is already defined" problem
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
case t.kind
@ -1071,8 +1145,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
else:
return false
proc insertDestructors(c: PContext, varSection: PNode):
tuple[outer: PNode, inner: PNode] =
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
# Accepts a var or let section.
#
# When a var section has variables with destructors
@ -1128,7 +1202,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
return
proc ImplicitelyDiscardable(n: PNode): bool =
proc ImplicitlyDiscardable(n: PNode): bool =
result = isCallExpr(n) and n.sons[0].kind == nkSym and
sfDiscardable in n.sons[0].sym.flags
@ -1179,7 +1253,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
# a statement list (s; e) has the type 'e':
if result.kind == nkStmtList and result.len > 0:
var lastStmt = lastSon(result)
if lastStmt.kind != nkNilLit and not ImplicitelyDiscardable(lastStmt):
if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt):
result.typ = lastStmt.typ
#localError(lastStmt.info, errGenerated,
# "Last expression must be explicitly returned if it " &

0
compiler/semtempl.nim Executable file → Normal file
View file

6
compiler/semthreads.nim Executable file → Normal file
View file

@ -311,6 +311,12 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
# container construction:
result = toNil # nothing until later
for i in 0..n.len-1: aggregateOwner(result, analyse(c, n[i]))
of nkObjConstr:
if n.typ != nil and containsGarbageCollectedRef(n.typ):
result = toMine
else:
result = toNil # nothing until later
for i in 1..n.len-1: aggregateOwner(result, analyse(c, n[i]))
of nkAddr, nkHiddenAddr:
var a = lvalueSym(n)
if a.kind == nkSym:

21
compiler/semtypes.nim Executable file → Normal file
View file

@ -45,7 +45,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
e = newSymS(skEnumField, n.sons[i].sons[0], c)
var v = semConstExpr(c, n.sons[i].sons[1])
var strVal: PNode = nil
case skipTypes(v.typ, abstractInst).kind
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
of tyTuple:
if sonsLen(v) == 2:
strVal = v.sons[1] # second tuple part is the string value
@ -222,10 +222,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
let bound = result.typ.sons[0].sym
if bound != nil:
return bound
else:
return result.typ.sym
else:
return result.typ.sym
return result
if result.typ.sym == nil:
LocalError(n.info, errTypeExpected)
return errorSym(c, n)
return result.typ.sym
if result.kind != skType:
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter
@ -323,8 +324,8 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var biggestInt): PNode
checkMinSonsLen(t, 1)
let ac = semConstExpr(c, a)
let bc = semConstExpr(c, b)
let at = fitNode(c, t.sons[0].typ, ac)
let bt = fitNode(c, t.sons[0].typ, bc)
let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
result = newNodeI(nkRange, a.info)
result.add(at)
@ -388,7 +389,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
return
incl(a.sons[0].sym.flags, sfDiscriminant)
var covered: biggestInt = 0
var typ = skipTypes(a.sons[0].Typ, abstractVar)
var typ = skipTypes(a.sons[0].Typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ):
LocalError(n.info, errSelectorMustBeOrdinal)
elif firstOrd(typ) < 0:
@ -873,6 +874,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.typ == nil:
if s.kind != skError: LocalError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
assert s.typ.len > 0
InternalAssert prev == nil
result = s.typ.sons[0]
elif prev == nil:
result = s.typ
else:

0
compiler/semtypinst.nim Executable file → Normal file
View file

View file

@ -73,6 +73,9 @@ proc serve*(action: proc (){.nimcall.}) =
var line = stdin.readLine.string
if line == "quit": quit()
execute line
echo ""
FlushFile(stdout)
of "tcp", "":
var server = Socket()
let p = getConfigVar("server.port")
@ -83,11 +86,10 @@ proc serve*(action: proc (){.nimcall.}) =
new(stdoutSocket)
while true:
accept(server, stdoutSocket)
discard stdoutSocket.recvLine(inp)
stdoutSocket.readLine(inp)
execute inp.string
stdoutSocket.send("\c\L")
stdoutSocket.close()
else:
echo "Invalid server.type:", typ
quit 1

146
compiler/sigmatch.nim Executable file → Normal file
View file

@ -97,6 +97,45 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.baseTypeMatch = b.baseTypeMatch
copyIdTable(a.bindings, b.bindings)
proc sumGeneric(t: PType): int =
var t = t
while true:
case t.kind
of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyArrayConstr,
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
t = t.lastSon
inc result
of tyVar:
# but do not make 'var T' more specific than 'T'!
t = t.sons[0]
of tyGenericInvokation, tyTuple:
result = ord(t.kind == tyGenericInvokation)
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
break
of tyGenericParam, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: break
else: return 0
proc complexDisambiguation(a, b: PType): int =
var x, y: int
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
result = x - y
when false:
proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
if a.len > 1 and b.len > 1:
let aa = a.sons[1].sumGeneric
let bb = b.sons[1].sumGeneric
var a = a
var b = b
if aa < bb: swap(a, b)
# all must be better
for i in 2 .. <min(a.len, b.len):
if not a.sons[i].betterThan(b.sons[i]): return 0
# a must be longer or of the same length as b:
result = a.len - b.len
proc cmpCandidates*(a, b: TCandidate): int =
result = a.exactMatches - b.exactMatches
if result != 0: return
@ -110,9 +149,12 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return
if (a.calleeScope != -1) and (b.calleeScope != -1):
result = a.calleeScope - b.calleeScope
if result != 0: return
if result != 0: return
# the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty
if result != 0: return
# prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee)
proc writeMatches*(c: TCandidate) =
Writeln(stdout, "exact matches: " & $c.exactMatches)
@ -129,12 +171,19 @@ proc NotFoundError*(c: PContext, n: PNode) =
# fail fast:
GlobalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1):
#debug(n.sons[i].typ)
for i in countup(1, sonsLen(n) - 1):
var nt = n.sons[i].typ
if n.sons[i].kind == nkExprEqExpr:
add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ")
let nt = n.sons[i].typ
if nt.isNil:
n.sons[i].sons[1] = c.semOperand(c, n.sons[i].sons[1])
nt = n.sons[i].sons[1].typ
n.sons[i].typ = nt
else:
if nt.isNil:
n.sons[i] = c.semOperand(c, n.sons[i])
nt = n.sons[i].typ
if nt.kind == tyError: return
add(result, typeToString(nt))
if i != sonsLen(n) - 1: add(result, ", ")
@ -146,7 +195,6 @@ proc NotFoundError*(c: PContext, n: PNode) =
if sym.kind in RoutineKinds:
add(candidates, getProcHeader(sym))
add(candidates, "\n")
#debug(sym.typ)
sym = nextOverloadIter(o, c, n.sons[0])
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
@ -314,6 +362,22 @@ proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone
proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
let
a0 = firstOrd(a)
a1 = lastOrd(a)
f0 = firstOrd(f)
f1 = lastOrd(f)
if a0 == f0 and a1 == f1:
result = isEqual
elif a0 >= f0 and a1 <= f1:
result = isConvertible
elif a0 <= f1 and f0 <= a1:
# X..Y and C..D overlap iff (X <= D and C <= Y)
result = isConvertible
else:
result = isNone
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f?
result = isNone
@ -338,6 +402,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = typeRel(c, base(f), base(a))
# bugfix: accept integer conversions here
#if result < isGeneric: result = isNone
if result notin {isNone, isGeneric}:
result = typeRangeRel(f, a)
elif skipTypes(f, {tyRange}).kind == a.kind:
result = isIntConv
elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
@ -655,7 +721,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
of isSubrange:
inc(m.subtypeMatches)
result = copyTree(arg)
#result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isGeneric:
inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
@ -669,7 +736,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f)
# BUG: f may not be the right key!
if skipTypes(result.typ, abstractVar).kind in {tyTuple}:
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
# BUGFIX: use ``result.typ`` and not `f` here
of isFromIntLit:
@ -680,7 +747,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isEqual:
inc(m.exactMatches)
result = copyTree(arg)
if skipTypes(f, abstractVar).kind in {tyTuple}:
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isNone:
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
@ -756,6 +823,28 @@ proc setSon(father: PNode, at: int, son: PNode) =
if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son
# we are allowed to modify the calling node in the 'prepare*' procs:
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
if formal.kind == tyExpr and formal.len != 1:
# {tyTypeDesc, tyExpr, tyStmt, tyProxy}:
# a.typ == nil is valid
result = a
elif a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
proc prepareOperand(c: PContext; a: PNode): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
proc prepareNamedParam(a: PNode) =
if a.sons[0].kind != nkIdent:
var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var TIntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} =
@ -780,6 +869,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if n.sons[a].kind == nkExprEqExpr:
# named param
# check if m.callee has such a param:
prepareNamedParam(n.sons[a])
if n.sons[a].sons[0].kind != nkIdent:
LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
m.state = csNoMatch
@ -795,9 +885,11 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch
return
m.baseTypeMatch = false
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
n.sons[a].typ = n.sons[a].sons[1].typ
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil:
if arg == nil:
m.state = csNoMatch
return
checkConstraint(n.sons[a].sons[1])
@ -809,30 +901,33 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if f != formalLen - 1: container = nil
else:
setSon(m.call, formal.position + 1, arg)
else:
else:
# unnamed param
if f >= formalLen:
if f >= formalLen:
# too many arguments?
if tfVarArgs in m.callee.flags:
if tfVarArgs in m.callee.flags:
# is ok... but don't increment any counters...
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
# we have no formal here to snoop at:
n.sons[a] = prepareOperand(c, n.sons[a])
if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
copyTree(n.sons[a]), m, c))
else:
else:
addSon(m.call, copyTree(n.sons[a]))
elif formal != nil:
m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil):
if (arg != nil) and m.baseTypeMatch and (container != nil):
addSon(container, arg)
else:
else:
m.state = csNoMatch
return
else:
return
else:
m.state = csNoMatch
return
else:
return
else:
if m.callee.n.sons[f].kind != nkSym:
InternalError(n.sons[a].info, "matches")
return
@ -843,6 +938,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch
return
m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if arg == nil:
@ -855,12 +951,18 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
if f != formalLen - 1: container = nil
else:
else:
setSon(m.call, formal.position + 1, arg)
checkConstraint(n.sons[a])
inc(a)
inc(f)
proc semFinishOperands*(c: PContext, n: PNode) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked:
for i in 1 .. <n.len:
n.sons[i] = prepareOperand(c, n.sons[i])
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support:
var marker = initIntSet()

0
compiler/suggest.nim Executable file → Normal file
View file

0
compiler/syntaxes.nim Executable file → Normal file
View file

0
compiler/tccgen.nim Executable file → Normal file
View file

11
compiler/transf.nim Executable file → Normal file
View file

@ -323,10 +323,10 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
# we don't include uint and uint64 here as these are no ordinal types ;-)
if not isOrdinalType(source):
# XXX int64 -> float conversion?
# float -> int conversions. ugh.
result = transformSons(c, n)
elif firstOrd(dest) <= firstOrd(source) and
lastOrd(source) <= lastOrd(dest):
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
# BUGFIX: simply leave n as it is; we need a nkConv node,
# but no range check:
result = transformSons(c, n)
@ -334,13 +334,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
# generate a range check:
if dest.kind == tyInt64 or source.kind == tyInt64:
result = newTransNode(nkChckRange64, n, 3)
else:
else:
result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar)
result[0] = transform(c, n.sons[1])
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
of tyFloat..tyFloat128:
of tyFloat..tyFloat128:
# XXX int64 -> float conversion?
if skipTypes(n.typ, abstractVar).kind == tyRange:
result = newTransNode(nkChckRangeF, n, 3)
dest = skipTypes(n.typ, abstractVar)

2
compiler/trees.nim Executable file → Normal file
View file

@ -115,7 +115,7 @@ proc isDeepConstExpr*(n: PNode): bool =
result = true
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar, nkClosure:
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false
result = true

0
compiler/treetab.nim Executable file → Normal file
View file

88
compiler/types.nim Executable file → Normal file
View file

@ -49,16 +49,18 @@ proc isOrdinalType*(t: PType): bool
proc enumHasHoles*(t: PType): bool
const
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable}
tyConst, tyMutable, tyTypeDesc}
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable}
tyConst, tyMutable, tyTypeDesc}
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
tyConst, tyMutable}
tyConst, tyMutable, tyTypeDesc}
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
tyConst, tyMutable}
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
tyConst, tyMutable, tyTypeDesc}
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal,
tyTypeDesc}
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
tyTypeDesc}
typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc}
@ -327,7 +329,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
result = false
if typ == nil: return
if tfAcyclic in typ.flags: return
var t = skipTypes(typ, abstractInst)
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
if tfAcyclic in t.flags: return
case t.kind
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray,
@ -344,11 +346,10 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
#if t.kind == tyObject and tfFinal notin t.flags:
# # damn inheritance may introduce cycles:
# result = true
of tyProc: result = typ.callConv == ccClosure
else: nil
proc canFormAcycle(typ: PType): bool =
# XXX as I expect cycles introduced by closures are very rare, we pretend
# they can't happen here.
proc canFormAcycle(typ: PType): bool =
var marker = InitIntSet()
result = canFormAcycleAux(marker, typ, typ.id)
@ -393,26 +394,31 @@ proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange)
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
"int", "int8", "int16", "int32", "int64",
"float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64",
"bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass"]
proc consToStr(t: PType): string =
if t.len > 0: result = t.typeToString
else: result = typeToStr[t.kind].strip
proc constraintsToStr(t: PType): string =
let sep = if tfAny in t.flags: " or " else: " and "
result = ""
for i in countup(0, t.sons.len - 1):
for i in countup(0, t.len - 1):
if i > 0: result.add(sep)
result.add(t.sons[i].typeToString)
result.add(t.sons[i].consToStr)
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
"int", "int8", "int16", "int32", "int64",
"float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64",
"bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass"]
var t = typ
result = ""
if t == nil: return
@ -433,12 +439,15 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
add(result, typeToString(t.sons[i]))
add(result, ']')
of tyTypeDesc:
if t.sons == nil or t.sons.len == 0: result = "typedesc"
if t.len == 0: result = "typedesc"
else: result = "typedesc[" & constraintsToStr(t) & "]"
of tyTypeClass:
result = constraintsToStr(t)
case t.len
of 0: result = "typeclass[]"
of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
else: result = constraintsToStr(t)
of tyExpr:
if t.sons.len == 0: result = "expr"
if t.len == 0: result = "expr"
else: result = "expr[" & constraintsToStr(t) & "]"
of tyArray:
if t.sons[0].kind == tyRange:
@ -476,8 +485,8 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
add(result, ']')
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
result = typeToStr[t.kind] & typeToString(t.sons[0])
of tyRange:
result = "range " & rangeToStr(t.n)
of tyRange:
result = "range " & rangeToStr(t.n) & "(" & typeToString(t.sons[0]) & ")"
of tyProc:
result = if tfIterator in t.flags: "iterator (" else: "proc ("
for i in countup(1, sonsLen(t) - 1):
@ -534,7 +543,7 @@ proc firstOrd(t: PType): biggestInt =
else:
assert(t.n.sons[0].kind == nkSym)
result = t.n.sons[0].sym.position
of tyGenericInst, tyDistinct, tyConst, tyMutable:
of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
result = firstOrd(lastSon(t))
else:
InternalError("invalid kind for first(" & $t.kind & ')')
@ -567,7 +576,7 @@ proc lastOrd(t: PType): biggestInt =
of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position
of tyGenericInst, tyDistinct, tyConst, tyMutable:
of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
result = lastOrd(lastSon(t))
of tyProxy: result = 0
else:
@ -833,7 +842,8 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
of tyGenericInst:
result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc:
if TypeDescExactMatch in c.flags:
if c.cmp == dcEqIgnoreDistinct: result = false
elif TypeDescExactMatch in c.flags:
CycleCheck()
result = sameChildrenAux(x, y, c) and sameFlags(a, b)
else:
@ -938,7 +948,8 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
of tyTypeClass:
match = matchTypeClass(bindings, req, t)
else: nil
elif t.kind in {tyObject}:
elif t.kind in {tyObject} and req.len != 0:
# empty 'object' is fine as constraint in a type class
match = sameType(t, req)
if tfAny in typeClass.flags:
@ -962,11 +973,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = true
if typ == nil: return
if ContainsOrIncl(marker, typ.id): return
var t = skipTypes(typ, abstractInst)
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
case t.kind
of tyVar:
if kind == skConst: return false
var t2 = skipTypes(t.sons[0], abstractInst)
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
case t2.kind
of tyVar:
result = false # ``var var`` is always an invalid type:
@ -980,8 +991,9 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
if not result: break
if result and t.sons[0] != nil:
result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc:
of tyExpr, tyStmt, tyTypeDesc:
result = true
# XXX er ... no? these should not be allowed!
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation,
tyTypeClass:
result = false
@ -994,7 +1006,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyGenericInst, tyDistinct:
result = typeAllowedAux(marker, lastSon(t), kind)
of tyRange:
result = skipTypes(t.sons[0], abstractInst).kind in
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
{tyChar, tyEnum, tyInt..tyFloat128}
of tyOpenArray, tyVarargs:
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
@ -1162,6 +1174,8 @@ proc computeSizeAux(typ: PType, a: var biggestInt): biggestInt =
result = align(result, a)
of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
result = computeSizeAux(lastSon(typ), a)
of tyTypeDesc:
result = (if typ.len == 1: computeSizeAux(typ.sons[0], a) else: -1)
of tyProxy: result = 1
else:
#internalError("computeSizeAux()")

0
compiler/wordrecg.nim Executable file → Normal file
View file

0
config/nimdoc.cfg Executable file → Normal file
View file

Some files were not shown because too many files have changed in this diff Show more