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

0
build.bat Executable file → Normal file
View file

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

@ -71,21 +71,25 @@ type
nkDotCall, # used to temporarily flag a nkCall node; nkDotCall, # used to temporarily flag a nkCall node;
# this is used # this is used
# for transforming ``s.len`` to ``len(s)`` # for transforming ``s.len`` to ``len(s)``
nkCommand, # a call like ``p 2, 4`` without parenthesis nkCommand, # a call like ``p 2, 4`` without parenthesis
nkCall, # a call like p(x, y) or an operation like +(a, b) nkCall, # a call like p(x, y) or an operation like +(a, b)
nkCallStrLit, # a call with a string literal nkCallStrLit, # a call with a string literal
# x"abc" has two sons: nkIdent, nkRStrLit # x"abc" has two sons: nkIdent, nkRStrLit
# x"""abc""" has two sons: nkIdent, nkTripleStrLit # 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'' nkExprEqExpr, # a named parameter with equals: ''expr = expr''
nkExprColonExpr, # a named parameter with colon: ''expr: expr'' nkExprColonExpr, # a named parameter with colon: ''expr: expr''
nkIdentDefs, # a definition like `a, b: typeDesc = expr` nkIdentDefs, # a definition like `a, b: typeDesc = expr`
# either typeDesc or expr may be nil; used in # either typeDesc or expr may be nil; used in
# formal parameters, var statements, etc. # formal parameters, var statements, etc.
nkVarTuple, # a ``var (a, b) = expr`` construct 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 nkPar, # syntactic (); may be a tuple constructor
nkObjConstr, # object constructor: T(a: 1, b: 2)
nkCurly, # syntactic {} nkCurly, # syntactic {}
nkCurlyExpr, # an expression like a{i} nkCurlyExpr, # an expression like a{i}
nkBracket, # syntactic [] nkBracket, # syntactic []
@ -109,7 +113,6 @@ type
nkHiddenStdConv, # an implicit standard type conversion nkHiddenStdConv, # an implicit standard type conversion
nkHiddenSubConv, # an implicit type conversion from a subtype nkHiddenSubConv, # an implicit type conversion from a subtype
# to a supertype # to a supertype
nkHiddenCallConv, # an implicit type conversion via a type converter
nkConv, # a type conversion nkConv, # a type conversion
nkCast, # a type cast nkCast, # a type cast
nkStaticExpr, # a static expr nkStaticExpr, # a static expr
@ -476,7 +479,7 @@ type
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym, mNCallSite, mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo mInstantiationInfo, mGetTypeInfo
@ -520,7 +523,7 @@ type
TNodeSeq* = seq[PNode] TNodeSeq* = seq[PNode]
PType* = ref TType PType* = ref TType
PSym* = ref TSym 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 typ*: PType
comment*: string comment*: string
info*: TLineInfo info*: TLineInfo
@ -591,6 +594,7 @@ type
TLib* = object of lists.TListEntry # also misused for headers! TLib* = object of lists.TListEntry # also misused for headers!
kind*: TLibKind kind*: TLibKind
generated*: bool # needed for the backends: generated*: bool # needed for the backends:
isOverriden*: bool
name*: PRope name*: PRope
path*: PNode # can be a string literal! path*: PNode # can be a string literal!
@ -605,7 +609,7 @@ type
PInstantiation* = ref TInstantiation PInstantiation* = ref TInstantiation
PLib* = ref TLib PLib* = ref TLib
TSym* = object of TIdObj TSym* {.acyclic.} = object of TIdObj
# proc and type instantiations are cached in the generic symbol # proc and type instantiations are cached in the generic symbol
case kind*: TSymKind case kind*: TSymKind
of skType: of skType:
@ -653,7 +657,8 @@ type
constraint*: PNode # additional constraints like 'lit|result' constraint*: PNode # additional constraints like 'lit|result'
TTypeSeq* = seq[PType] 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 # same id; there may be multiple copies of a type
# in memory! # in memory!
kind*: TTypeKind # kind of type kind*: TTypeKind # kind of type
@ -759,7 +764,7 @@ const
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5! dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit} nkCommand, nkCallStrLit, nkHiddenCallConv}
nkLambdaKinds* = {nkLambda, nkDo} nkLambdaKinds* = {nkLambda, nkDo}
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} 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] result = n.sons[1]
else: result = n else: result = n
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
proc SameValue*(a, b: PNode): bool = proc SameValue*(a, b: PNode): bool =
result = false result = false
case a.kind case a.kind

View file

@ -60,7 +60,7 @@ iterator chosen(packages: PStringTable): string =
proc addBabelPath(p: string, info: TLineInfo) = proc addBabelPath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p): if not contains(options.searchPaths, p):
Message(info, hintPath, p) if gVerbosity >= 1: Message(info, hintPath, p)
lists.PrependStr(options.lazyPaths, p) lists.PrependStr(options.lazyPaths, p)
proc addPathWithNimFiles(p: string, info: TLineInfo) = proc addPathWithNimFiles(p: string, info: TLineInfo) =
@ -83,7 +83,7 @@ proc addPathRec(dir: string, info: TLineInfo) =
if k == pcDir and p[pos] != '.': if k == pcDir and p[pos] != '.':
addPackage(packages, p) addPackage(packages, p)
for p in packages.chosen: for p in packages.chosen:
addPathWithNimFiles(p, info) addBabelPath(p, info)
proc babelPath*(path: string, info: TLineInfo) = proc babelPath*(path: string, info: TLineInfo) =
addPathRec(path, info) 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 # c2nim - C to Nimrod source converter
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -15,7 +15,7 @@ const
Version = NimrodVersion Version = NimrodVersion
Usage = """ Usage = """
c2nim - C to Nimrod source converter c2nim - C to Nimrod source converter
(c) 2012 Andreas Rumpf (c) 2013 Andreas Rumpf
Usage: c2nim [options] inputfile [options] Usage: c2nim [options] inputfile [options]
Options: Options:
-o, --out:FILE set output filename -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) result = newNodeP(nkConstSection, p)
getTok(p, result) getTok(p, result)
var i = 0 var i = 0
var hasUnknown = false
while true: while true:
var name = skipIdentExport(p) var name = skipIdentExport(p)
var val: PNode var val: PNode
if p.tok.xkind == pxAsgn: if p.tok.xkind == pxAsgn:
getTok(p, name) getTok(p, name)
val = constantExpression(p) val = constantExpression(p)
if val.kind == nkIntLit: i = int(val.intVal)+1 if val.kind == nkIntLit:
else: parMessage(p, errXExpected, "int literal") i = int(val.intVal)+1
hasUnknown = false
else:
hasUnknown = true
else: else:
if hasUnknown:
parMessage(p, warnUser, "computed const value may be wrong: " &
name.renderTree)
val = newIntNodeP(nkIntLit, i, p) val = newIntNodeP(nkIntLit, i, p)
inc(i) inc(i)
var c = createConst(name, ast.emptyNode, val, p) 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
#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 void (*callback_t) (int rc);
typedef const char* (*callback2)(int rc, long L, const char* buffer); 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 # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

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)) addrLoc(dest), rdLoc(src))
if needToKeepAlive in flags: keepAlive(p, dest) 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) = proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# Consider: # Consider:
# type TMyFastString {.shallow.} = string # 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", linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
addrLoc(dest), rdLoc(src)) addrLoc(dest), rdLoc(src))
if needToKeepAlive in flags: keepAlive(p, dest) 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? # XXX: check for subtyping?
if needsComplexAssignment(dest.t): 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: else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyArray, tyArrayConstr: 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 discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = a.t 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) = proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
var ty = genRecordFieldAux(p, e, d, a) 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]) appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, 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 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) = 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: if optFieldCheck in p.options:
var
a: TLoc
f, field: PSym
ty: PType
r: PRope
ty = genRecordFieldAux(p, e.sons[0], d, a) ty = genRecordFieldAux(p, e.sons[0], d, a)
r = rdLoc(a) r = rdLoc(a)
f = e.sons[0].sons[1].sym 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 == nil: InternalError(e.info, "genCheckedRecordField")
if field.loc.r == nil: if field.loc.r == nil:
InternalError(e.info, "genCheckedRecordField") # generate the checks: InternalError(e.info, "genCheckedRecordField") # generate the checks:
for i in countup(1, sonsLen(e) - 1): genFieldCheck(p, e, r, field)
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)
app(r, rfmt(nil, ".$1", field.loc.r)) app(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r)
else: else:
@ -913,10 +975,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = x; # seq->data[seq->len-1] = x;
let seqAppendPattern = if gCmd != cmdCompileToCpp: let seqAppendPattern = if gCmd != cmdCompileToCpp:
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n" "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else: else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n" "$1 = ($2) #incrSeq($1, sizeof($3));$n"
var a, b, dest: TLoc var a, b, dest: TLoc
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
@ -935,20 +996,12 @@ proc genReset(p: BProc, n: PNode) =
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))) addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
proc genNew(p: BProc, e: PNode) = proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
var var sizeExpr = sizeExpr
a, b: TLoc let refType = skipTypes(a.t, abstractVarRange)
reftype, bt: PType var b: TLoc
sizeExpr: PRope
refType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a)
initLoc(b, locExpr, a.t, OnHeap) initLoc(b, locExpr, a.t, OnHeap)
# 'genNew' also handles 'unsafeNew': if sizeExpr.isNil:
if e.len == 3:
var se: TLoc
InitLocExpr(p, e.sons[2], se)
sizeExpr = se.rdLoc
else:
sizeExpr = ropef("sizeof($1)", sizeExpr = ropef("sizeof($1)",
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))) getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
let args = [getTypeDesc(p.module, reftype), let args = [getTypeDesc(p.module, reftype),
@ -965,9 +1018,20 @@ proc genNew(p: BProc, e: PNode) =
else: else:
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args) b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
genAssignment(p, a, b, {needToKeepAlive}) # set the object type: 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) 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) = proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
let seqtype = skipTypes(dest.t, abstractVarRange) let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype), let args = [getTypeDesc(p.module, seqtype),
@ -975,7 +1039,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
var call: TLoc var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap) initLoc(call, locExpr, dest.t, OnHeap)
if dest.s == OnHeap and usesNativeGC(): 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) call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
else: else:
@ -988,6 +1055,44 @@ proc genNewSeq(p: BProc, e: PNode) =
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
genNewSeqAux(p, a, b.rdLoc) 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) = proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
var arr: TLoc var arr: TLoc
if d.k == locNone: 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: # generate call to newSeq before adding the elements per hand:
genNewSeqAux(p, d, intLiteral(sonsLen(t))) genNewSeqAux(p, d, intLiteral(sonsLen(t)))
for i in countup(0, sonsLen(t) - 1): 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.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
arr.s = OnHeap # we know that sequences are on the heap arr.s = OnHeap # we know that sequences are on the heap
expr(p, t.sons[i], arr) 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 var a, b, x, y: TLoc
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]): if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set: # a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons # do not emit the set, but generate a bunch of comparisons; and if we do
initLocExpr(p, e.sons[2], a) # 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) initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(") b.r = toRope("(")
var length = sonsLen(e.sons[1]) 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 mNewFinalize: genNewFinalize(p, e)
of mNewSeq: genNewSeq(p, e) of mNewSeq: genNewSeq(p, e)
of mSizeOf: of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))", 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 mChr: genCast(p, e, d)
of mOrd: genOrd(p, e, d) of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@ -1755,6 +1867,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
exprComplexConst(p, e, d) exprComplexConst(p, e, d)
else: else:
genTupleConstr(p, e, d) genTupleConstr(p, e, d)
of nkObjConstr: genObjConstr(p, e, d)
of nkCast: genCast(p, e, d) of nkCast: genCast(p, e, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d)
of nkHiddenAddr, nkAddr: genAddr(p, e, d) of nkHiddenAddr, nkAddr: genAddr(p, e, d)

View file

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

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

@ -16,7 +16,8 @@ const
# above X strings a hash-switch for strings is generated # above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) = 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 # we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-) # that it works out of the box for thread local storage then :-)
let prc = genTraverseProcForGlobal(p.module, v) let prc = genTraverseProcForGlobal(p.module, v)
@ -44,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
if t.kind == tyTuple: if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)]) field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else: 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", field.r = ropef("$1.$2",
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]) [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field) putLocIntoDest(p, v.loc, field)
@ -63,19 +64,23 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
result = len(p.blocks) result = len(p.blocks)
setlen(p.blocks, result + 1) setlen(p.blocks, result + 1)
p.blocks[result].id = p.labels 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.} = proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope) b.label = con("LA", b.id.toRope)
result = b.label result = b.label
proc blockBody(b: var TBlock): PRope {.inline.} = proc blockBody(b: var TBlock): PRope =
return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts]) 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) = 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 # 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) setlen(p.blocks, topBlock)
# this is done after the block is popped so $n is # this is done after the block is popped so $n is
# properly indented when pretty printing is enabled # properly indented when pretty printing is enabled
@ -83,10 +88,13 @@ proc endBlock(p: BProc, blockEnd: PRope) =
proc endBlock(p: BProc) = proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1 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) rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
else: else:
~"}$n" ~"}$n"
let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0:
blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
endBlock(p, blockEnd) endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@ -799,12 +807,9 @@ proc genPragma(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
case whichPragma(it) case whichPragma(it)
of wEmit: of wEmit: genEmit(p, it)
genEmit(p, it) of wBreakpoint: genBreakPoint(p, it)
of wBreakpoint: of wWatchpoint: genWatchpoint(p, it)
genBreakPoint(p, it)
of wWatchpoint:
genWatchpoint(p, it)
else: nil else: nil
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = 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 if typ == nil: return
var p = c.p var p = c.p
case typ.kind case typ.kind
of tyGenericInst, tyGenericBody: of tyGenericInst, tyGenericBody, tyTypeDesc:
genTraverseProc(c, accessor, lastSon(typ)) genTraverseProc(c, accessor, lastSon(typ))
of tyArrayConstr, tyArray: of tyArrayConstr, tyArray:
let arraySize = lengthOrd(typ.sons[0]) 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) lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p c.p = p
assert typ.kind != tyTypedesc
if typ.kind == tySequence: if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ) genTraverseProcSeq(c, "a".toRope, typ)
else: 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: # C's arrays are broken beyond repair:
genTraverseProc(c, "a".toRope, typ.sons[0]) genTraverseProc(c, "a".toRope, typ.sons[0])
else: else:

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

@ -194,7 +194,7 @@ proc mapType(typ: PType): TCTypeKind =
else: internalError("mapType") else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0]) of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef: of tyPtr, tyVar, tyRef:
var base = skipTypes(typ.sons[0], abstractInst) var base = skipTypes(typ.sons[0], typedescInst)
case base.kind case base.kind
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
else: result = ctPtr else: result = ctPtr
@ -208,7 +208,7 @@ proc mapType(typ: PType): TCTypeKind =
else: InternalError("mapType") else: InternalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind = 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) else: result = mapType(typ)
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope
@ -224,10 +224,10 @@ proc isInvalidReturnType(rettype: PType): bool =
else: else:
case mapType(rettype) case mapType(rettype)
of ctArray: of ctArray:
result = not (skipTypes(rettype, abstractInst).kind in result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyRef, tyPtr}) {tyVar, tyRef, tyPtr})
of ctStruct: of ctStruct:
result = needsComplexAssignment(skipTypes(rettype, abstractInst)) result = needsComplexAssignment(skipTypes(rettype, typedescInst))
else: result = false else: result = false
const const
@ -253,7 +253,7 @@ proc getGlobalTempName(): PRope =
result = rfmt(nil, "TMP$1", toRope(backendId())) result = rfmt(nil, "TMP$1", toRope(backendId()))
proc ccgIntroducedPtr(s: PSym): bool = proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, abstractInst) var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind assert skResult != s.kind
if tfByRef in pt.flags: return true if tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false 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 = proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
when false: when false:
if t.Kind in {tyRef, tyPtr, tyVar}: 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: if b.kind == tySet and mapSetType(b) == ctArray:
return getTypeDescAux(m, b, check) return getTypeDescAux(m, b, check)
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
proc paramStorageLoc(param: PSym): TStorageLoc = 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 result = OnStack
else: else:
result = OnUnknown result = OnUnknown
@ -572,7 +572,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
assert(CacheGetType(m.typeCache, t) == nil) assert(CacheGetType(m.typeCache, t) == nil)
IdTablePut(m.typeCache, t, con(result, "*")) IdTablePut(m.typeCache, t, con(result, "*"))
if not isImportedType(t): if not isImportedType(t):
if skipTypes(t.sons[0], abstractInst).kind != tyEmpty: if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const const
cppSeq = "struct $2 : #TGenericSeq {$n" cppSeq = "struct $2 : #TGenericSeq {$n"
cSeq = "struct $2 {$n" & cSeq = "struct $2 {$n" &
@ -744,7 +744,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
if objType.sym == nil: if objType.sym == nil:
InternalError(d.info, "anonymous obj with discriminator") InternalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [ 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 = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
@ -915,7 +915,7 @@ include ccgtrav
proc genTypeInfo(m: BModule, typ: PType): PRope = proc genTypeInfo(m: BModule, typ: PType): PRope =
var t = getUniqueType(typ) var t = getUniqueType(typ)
result = ropef("NTI$1", [toRope(t.id)]) 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: if owner != m.module:
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfo(owner.bmod, typ) 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 # no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``. # produced instead of ``NI``.
result = key result = key
of tyEmpty, tyNil, tyExpr, tyStmt, tyTypeDesc, tyPointer, tyString, of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
tyCString, tyNone, tyBigNum: tyCString, tyNone, tyBigNum:
result = gCanonicalTypes[k] result = gCanonicalTypes[k]
if result == nil: if result == nil:
gCanonicalTypes[k] = key gCanonicalTypes[k] = key
result = key result = key
of tyGenericParam, tyTypeClass: of tyGenericParam, tyTypeClass, tyTypeDesc:
InternalError("GetUniqueType") InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key)) result = GetUniqueType(lastSon(key))

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

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

View file

@ -54,9 +54,10 @@ type
id*: int # the ID of the label; positive means that it id*: int # the ID of the label; positive means that it
label*: PRope # generated text for the label label*: PRope # generated text for the label
# nil if label is not used # nil if label is not used
nestedTryStmts*: int # how many try statements is it nested into
sections*: TCProcSections # the code beloging sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop 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 TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to 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 options*: TOptions # options that should be used for code
# generation; this is the same as prc.options # generation; this is the same as prc.options
# unless prc == nil # unless prc == nil
frameLen*: int # current length of frame descriptor maxFrameLen*: int # max length of frame descriptor
sendClosure*: PType # closure record type that we pass
receiveClosure*: PType # closure record type that we get
module*: BModule # used to prevent excessive parameter passing module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop withinLoop*: int # > 0 if we are within a loop
gcFrameId*: natural # for the GC stack marking 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 = proc relevantCol(methods: TSymSeq, col: int): bool =
# returns true iff the position is relevant # returns true iff the position is relevant
var t = methods[0].typ.sons[col] var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
if skipTypes(t, skipPtrs).kind == tyObject: if t.kind == tyObject:
for i in countup(1, high(methods)): for i in countup(1, high(methods)):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs) let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t): if not SameType(t2, t):

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

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

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

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

@ -10,7 +10,7 @@
# This module handles the conditional symbols. # This module handles the conditional symbols.
import import
ast, astalgo, msgs, hashes, platform, strutils, idents ast, astalgo, hashes, platform, strutils, idents
var gSymbols*: TStrTable var gSymbols*: TStrTable
@ -35,14 +35,12 @@ proc isDefined*(symbol: PIdent): bool =
proc isDefined*(symbol: string): bool = proc isDefined*(symbol: string): bool =
result = isDefined(getIdent(symbol)) result = isDefined(getIdent(symbol))
proc ListSymbols*() = iterator definedSymbolNames*: string =
var it: TTabIter var it: TTabIter
var s = InitTabIter(it, gSymbols) var s = InitTabIter(it, gSymbols)
OutWriteln("-- List of currently defined symbols --")
while s != nil: while s != nil:
if s.position == 1: OutWriteln(s.name.s) if s.position == 1: yield s.name.s
s = nextIter(it, gSymbols) s = nextIter(it, gSymbols)
OutWriteln("-- End of list --")
proc countDefinedSymbols*(): int = proc countDefinedSymbols*(): int =
var it: TTabIter 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 else: nil
proc packObject(x: PNode, typ: PType, res: pointer) = proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind == nkPar InternalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets: # compute the field's offsets:
discard typ.getSize 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] var it = x.sons[i]
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym internalAssert it.sons[0].kind == nkSym
@ -257,11 +257,11 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
unpackObjectAdd(x, typ.n, result) unpackObjectAdd(x, typ.n, result)
else: else:
result = n result = n
if result.kind != nkPar: if result.kind notin {nkObjConstr, nkPar}:
GlobalError(n.info, "cannot map value from FFI") GlobalError(n.info, "cannot map value from FFI")
if typ.n.isNil: if typ.n.isNil:
GlobalError(n.info, "cannot unpack unnamed tuple") 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] var it = n.sons[i]
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym internalAssert it.sons[0].kind == nkSym

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

@ -249,7 +249,7 @@ proc getNullValueAux(obj: PNode, result: PNode) =
else: InternalError(result.info, "getNullValueAux") else: InternalError(result.info, "getNullValueAux")
proc getNullValue(typ: PType, info: TLineInfo): PNode = proc getNullValue(typ: PType, info: TLineInfo): PNode =
var t = skipTypes(typ, abstractRange) var t = skipTypes(typ, abstractRange-{tyTypeDesc})
result = emptyNode result = emptyNode
case t.kind case t.kind
of tyBool, tyEnum, tyChar, tyInt..tyInt64: of tyBool, tyEnum, tyChar, tyInt..tyInt64:
@ -274,6 +274,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
for i in countup(0, int(lengthOrd(t)) - 1): for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info)) addSon(result, getNullValue(elemType(t), info))
of tyTuple: of tyTuple:
# XXX nkExprColonExpr is out of fashion ...
result = newNodeIT(nkPar, info, t) 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 p = newNodeIT(nkExprColonExpr, info, t.sons[i])
@ -295,6 +296,8 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
#assert(a.sons[0].kind == nkSym) can happen for transformed vars #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], {}) result = evalAux(c, a.sons[2], {})
if result.kind in {nkType..nkNilLit}:
result = result.copyNode
if isSpecial(result): return if isSpecial(result): return
else: else:
result = getNullValue(a.sons[0].typ, a.sons[0].info) result = getNullValue(a.sons[0].typ, a.sons[0].info)
@ -451,22 +454,28 @@ proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return if isSpecial(result): return
var x = result var x = result
if x.kind != nkPar: return raiseCannotEval(c, n.info) if x.kind != nkPar: return raiseCannotEval(c, n.info)
# this is performance critical:
var field = n.sons[1].sym var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1): result = x.sons[field.position]
var it = x.sons[i] if result.kind == nkExprColonExpr: result = result.sons[1]
if it.kind != nkExprColonExpr: if not aliasNeeded(result, flags): result = copyTree(result)
# lookup per index: when false:
result = x.sons[field.position] var field = n.sons[1].sym
if result.kind == nkExprColonExpr: result = result.sons[1] for i in countup(0, sonsLen(x) - 1):
if not aliasNeeded(result, flags): result = copyTree(result) var it = x.sons[i]
return if it.kind != nkExprColonExpr:
#InternalError(it.info, "evalFieldAccess") # lookup per index:
if it.sons[0].sym.name.id == field.name.id: result = x.sons[field.position]
result = x.sons[i].sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result) if not aliasNeeded(result, flags): result = copyTree(result)
return return
stackTrace(c, n, errFieldXNotFound, field.name.s) #InternalError(it.info, "evalFieldAccess")
result = emptyNode 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 = proc evalAsgn(c: PEvalContext, n: PNode): PNode =
var a = n.sons[0] var a = n.sons[0]
@ -896,13 +905,13 @@ proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
if sonsLen(ast) != 1: if sonsLen(ast) != 1:
GlobalError(code.info, errExprExpected, "multiple statements") GlobalError(code.info, errExprExpected, "multiple statements")
result = ast.sons[0] result = ast.sons[0]
result.typ = newType(tyExpr, c.module) #result.typ = newType(tyExpr, c.module)
proc evalParseStmt(c: PEvalContext, n: PNode): PNode = proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
var code = evalAux(c, n.sons[1], {}) var code = evalAux(c, n.sons[1], {})
result = parseString(code.getStrValue, code.info.toFilename, result = parseString(code.getStrValue, code.info.toFilename,
code.stringStartingLine) code.stringStartingLine)
result.typ = newType(tyStmt, c.module) #result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(n: PNode, context: PSym): PNode = proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true ## XXX: This should be pretty much guaranteed to be true
@ -994,9 +1003,9 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
case expandedSym.kind case expandedSym.kind
of skTemplate: of skTemplate:
let genSymOwner = if c.tos != nil and c.tos.prc != nil: let genSymOwner = if c.tos != nil and c.tos.prc != nil:
c.tos.prc c.tos.prc
else: else:
c.module c.module
result = evalTemplate(macroCall, expandedSym, genSymOwner) result = evalTemplate(macroCall, expandedSym, genSymOwner)
of skMacro: of skMacro:
# At this point macroCall.sons[0] is nkSym node. # 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}) result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return if isSpecial(result): return
addSon(a, result) addSon(a, result)
result = emptyNode result = a
of mNAddMultiple: of mNAddMultiple:
result = evalAux(c, n.sons[1], {efLValue}) result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return if isSpecial(result): return
@ -1098,7 +1107,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[2], {efLValue}) result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return if isSpecial(result): return
for i in countup(0, sonsLen(result) - 1): addSon(a, result.sons[i]) for i in countup(0, sonsLen(result) - 1): addSon(a, result.sons[i])
result = emptyNode result = a
of mNDel: of mNDel:
result = evalAux(c, n.sons[1], {efLValue}) result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return if isSpecial(result): return
@ -1341,13 +1350,21 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode result = emptyNode
dec(gNestedEvals) dec(gNestedEvals)
if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations) if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations)
case n.kind # atoms: case n.kind
of nkEmpty: result = n
of nkSym: result = evalSym(c, n, flags) of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: result = copyNode(n) # end of atoms of nkType..nkNilLit:
of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkInfix, # nkStrLit is VERY common in the traces, so we should avoid
nkPrefix, nkPostfix: # the 'copyNode' here.
result = n #.copyNode
of nkAsgn, nkFastAsgn: result = evalAsgn(c, n)
of nkCommand..nkHiddenCallConv:
result = evalMagicOrCall(c, n) result = evalMagicOrCall(c, n)
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: of nkCurly, nkBracket, nkRange:
# flags need to be passed here for mNAddMultiple :-( # flags need to be passed here for mNAddMultiple :-(
# XXX this is not correct in every case! # XXX this is not correct in every case!
@ -1370,12 +1387,23 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return if isSpecial(result): return
a.sons[i] = result a.sons[i] = result
result = a result = a
of nkBracketExpr: result = evalArrayAccess(c, n, flags) of nkObjConstr:
of nkDotExpr: result = evalFieldAccess(c, n, flags) let t = skipTypes(n.typ, abstractInst)
of nkDerefExpr, nkHiddenDeref: result = evalDeref(c, n, flags) var a: PNode
of nkAddr, nkHiddenAddr: result = evalAddr(c, n, flags) if t.kind == tyRef:
of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = evalConv(c, n) result = newNodeIT(nkRefTy, n.info, t)
of nkAsgn, nkFastAsgn: result = evalAsgn(c, n) 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 nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
of nkWhileStmt: result = evalWhile(c, n) of nkWhileStmt: result = evalWhile(c, n)
of nkCaseStmt: result = evalCase(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) result = raiseCannotEval(c, n.info)
of nkRefTy: of nkRefTy:
result = evalAux(c, n.sons[0], flags) 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) else: InternalError(n.info, "evalAux: " & $n.kind)
if result == nil: if result == nil:
InternalError(n.info, "evalAux: returned nil " & $n.kind) 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 c.callsite = nOrig
var s = newStackFrame() var s = newStackFrame()
s.call = n s.call = n
setlen(s.params, n.len) var L = n.safeLen
if L == 0: L = 1
setlen(s.params, L)
# return value: # return value:
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0]) s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
# setup parameters: # 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) pushStackFrame(c, s)
discard eval(c, sym.getBody) discard eval(c, sym.getBody)
result = s.params[0] result = s.params[0]
@ -1483,7 +1516,13 @@ proc myOpen(module: PSym): PPassContext =
pushStackFrame(c, newStackFrame()) pushStackFrame(c, newStackFrame())
result = c result = c
var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode = 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) result = eval(PEvalContext(c), n)
const evalPass* = makePass(myOpen, nil, myProcess, myProcess) const evalPass* = makePass(myOpen, nil, myProcess, myProcess)

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

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -391,33 +391,6 @@ proc resetCompilationLists* =
initLinkedList(externalToCompile) initLinkedList(externalToCompile)
initLinkedList(toLink) 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) = proc addFileToLink*(filename: string) =
prependStr(toLink, filename) prependStr(toLink, filename)
# BUGFIX: was ``appendStr`` # BUGFIX: was ``appendStr``
@ -536,6 +509,34 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
"nimrod", quoteIfContainsWhite(getPrefixDir()), "nimrod", quoteIfContainsWhite(getPrefixDir()),
"lib", quoteIfContainsWhite(libpath)]) "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, proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
isExternal: bool) = isExternal: bool) =
var it = PStrEntry(list.head) var it = PStrEntry(list.head)
@ -572,7 +573,12 @@ proc CallCCompiler*(projectfile: string) =
else: else:
res = execProcesses(cmds, {poUseShell, poParentStreams}, res = execProcesses(cmds, {poUseShell, poParentStreams},
gNumberOfProcessors) 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: if optNoLinking notin gGlobalOptions:
# call the linker: # call the linker:
var it = PStrEntry(toLink.head) var it = PStrEntry(toLink.head)

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

@ -98,6 +98,12 @@ proc parseLine(p: var TTmplParser) =
of wElif, wOf, wElse, wExcept, wFinally: of wElif, wOf, wElse, wExcept, wFinally:
LLStreamWrite(p.outp, repeatChar(p.indent - 2)) LLStreamWrite(p.outp, repeatChar(p.indent - 2))
LLStreamWrite(p.outp, substr(p.x, d)) LLStreamWrite(p.outp, substr(p.x, d))
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: else:
LLStreamWrite(p.outp, repeatChar(p.indent)) LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d)) LLStreamWrite(p.outp, substr(p.x, d))

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

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

@ -20,22 +20,22 @@ import
# implementation # implementation
type type
TEcmasGen = object of TPassContext TJSGen = object of TPassContext
module: PSym module: PSym
BModule = ref TEcmasGen BModule = ref TJSGen
TEcmasTypeKind = enum # necessary JS "types" TJSTypeKind = enum # necessary JS "types"
etyNone, # no type etyNone, # no type
etyNull, # null type etyNull, # null type
etyProc, # proc type etyProc, # proc type
etyBool, # bool type etyBool, # bool type
etyInt, # Ecmascript's int etyInt, # JavaScript's int
etyFloat, # Ecmascript's float etyFloat, # JavaScript's float
etyString, # Ecmascript's string etyString, # JavaScript's string
etyObject, # Ecmascript's reference to an object etyObject, # JavaScript's reference to an object
etyBaseIndex # base + index needed etyBaseIndex # base + index needed
TCompRes{.final.} = object TCompRes{.final.} = object
kind: TEcmasTypeKind kind: TJSTypeKind
com: PRope # computation part com: PRope # computation part
# address if this is a (address, index)-tuple # address if this is a (address, index)-tuple
res: PRope # result part; index if this is an res: PRope # result part; index if this is an
@ -44,7 +44,6 @@ type
TBlock{.final.} = object TBlock{.final.} = object
id: int # the ID of the label; positive means that it id: int # the ID of the label; positive means that it
# has been used (i.e. the label should be emitted) # 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' isLoop: bool # whether it's a 'block' or 'while'
TGlobals{.final.} = object TGlobals{.final.} = object
@ -57,12 +56,11 @@ type
TProc{.final.} = object TProc{.final.} = object
procDef: PNode procDef: PNode
prc: PSym prc: PSym
data: PRope locals: PRope
options: TOptions options: TOptions
module: BModule module: BModule
g: PGlobals g: PGlobals
BeforeRetNeeded: bool BeforeRetNeeded: bool
nestedTryStmts: int
unique: int unique: int
blocks: seq[TBlock] blocks: seq[TBlock]
@ -91,7 +89,7 @@ const
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs} tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
proc mapType(typ: PType): TEcmasTypeKind = proc mapType(typ: PType): TJSTypeKind =
var t = skipTypes(typ, abstractInst) var t = skipTypes(typ, abstractInst)
case t.kind case t.kind
of tyVar, tyRef, tyPtr: 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)): ((p.prc == nil) or not (sfPure in p.prc.flags)):
appf(r.com, "F.line = $1;$n", [toRope(line)]) 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) = proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
var var
cond, stmt: TCompRes cond, stmt: TCompRes
@ -498,7 +492,6 @@ proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
length = len(p.blocks) length = len(p.blocks)
setlen(p.blocks, length + 1) setlen(p.blocks, length + 1)
p.blocks[length].id = - p.unique p.blocks[length].id = - p.unique
p.blocks[length].nestedTryStmts = p.nestedTryStmts
p.blocks[length].isLoop = true p.blocks[length].isLoop = true
labl = p.unique labl = p.unique
gen(p, n.sons[0], cond) 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) if optStackTrace in p.Options: app(r.com, "framePtr = F;" & tnl)
app(r.com, "try {" & tnl) app(r.com, "try {" & tnl)
length = sonsLen(n) length = sonsLen(n)
inc(p.nestedTryStmts)
genStmt(p, n.sons[0], a) genStmt(p, n.sons[0], a)
app(r.com, mergeStmt(a)) app(r.com, mergeStmt(a))
i = 1 i = 1
@ -571,8 +563,6 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) =
appf(epart, "$1}$n", [mergeStmt(a)]) appf(epart, "$1}$n", [mergeStmt(a)])
inc(i) inc(i)
if epart != nil: appf(r.com, "} catch (EXC) {$n$1", [epart]) 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) app(r.com, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
if (i < length) and (n.sons[i].kind == nkFinally): if (i < length) and (n.sons[i].kind == nkFinally):
genStmt(p, n.sons[i].sons[0], a) 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]) if cond.com != nil: appf(r.com, "$1;$n", [cond.com])
stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
if stringSwitch: if stringSwitch:
useMagic(p, "toEcmaStr") useMagic(p, "toJSStr")
appf(r.com, "switch (toEcmaStr($1)) {$n", [cond.res]) appf(r.com, "switch (toJSStr($1)) {$n", [cond.res])
else: else:
appf(r.com, "switch ($1) {$n", [cond.res]) appf(r.com, "switch ($1) {$n", [cond.res])
for i in countup(1, sonsLen(n) - 1): 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]) v = copyNode(e.sons[0])
while (v.intVal <= e.sons[1].intVal): while (v.intVal <= e.sons[1].intVal):
gen(p, v, cond) 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]) appf(r.com, "case $1: ", [cond.res])
Inc(v.intVal) Inc(v.intVal)
else: else:
gen(p, e, cond) gen(p, e, cond)
if cond.com != nil: internalError(e.info, "ecmasgen.genCaseStmt") if cond.com != nil: internalError(e.info, "jsgen.genCaseStmt")
if stringSwitch: if stringSwitch:
case e.kind case e.kind
of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ", of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ",
[makeJSString(e.strVal)]) [makeJSString(e.strVal)])
else: InternalError(e.info, "ecmasgen.genCaseStmt: 2") else: InternalError(e.info, "jsgen.genCaseStmt: 2")
else: else:
appf(r.com, "case $1: ", [cond.res]) appf(r.com, "case $1: ", [cond.res])
genStmt(p, lastSon(it), stmt) genStmt(p, lastSon(it), stmt)
@ -637,7 +627,7 @@ proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkElse: of nkElse:
genStmt(p, it.sons[0], stmt) genStmt(p, it.sons[0], stmt)
appf(r.com, "default: $n$1break;$n", [mergeStmt(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", []) appf(r.com, "}$n", [])
proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes) 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 sym.loc.a = idx
setlen(p.blocks, idx + 1) setlen(p.blocks, idx + 1)
p.blocks[idx].id = - p.unique # negative because it isn't used yet p.blocks[idx].id = - p.unique # negative because it isn't used yet
p.blocks[idx].nestedTryStmts = p.nestedTryStmts
labl = p.unique labl = p.unique
if n.kind == nkBlockExpr: genStmtListExpr(p, n.sons[1], r) if n.kind == nkBlockExpr: genStmtListExpr(p, n.sons[1], r)
else: genStmt(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: if idx < 0 or not p.blocks[idx].isLoop:
InternalError(n.info, "no loop to break") InternalError(n.info, "no loop to break")
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used 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)]) appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])
proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) = 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 case n.sons[i].Kind
of nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal) of nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal)
of nkSym: app(r.com, mangleName(n.sons[i].sym)) 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) = proc genIfStmt(p: var TProc, n: PNode, r: var TCompRes) =
var var
@ -758,7 +746,7 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
const const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
nkCommand, nkHiddenCallConv, nkCallStrLit} 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): elif not p.g.generatedSyms.containsOrIncl(s.id):
var r2: TCompRes var r2: TCompRes
genProc(p, s, r2) genProc(p, s, r2)
app(p.g.code, mergeStmt(r2)) app(p.locals, mergeStmt(r2))
#app(r.com, mergeStmt(r2))
else: else:
if s.loc.r == nil: if s.loc.r == nil:
InternalError(n.info, "symbol has no generated name: " & s.name.s) 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): if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
genLineDir(p, c.ast, r) genLineDir(p, c.ast, r)
genVarInit(p, c, c.ast, r) genVarInit(p, c, c.ast, r)
app(p.g.code, r.com)
r.com = nil
when false: when false:
proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) = 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") binaryStmt(p, n, r, "", "$1 += $2")
else: else:
binaryStmt(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)") 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 mAppendSeqElem: binaryStmt(p, n, r, "", "$1.push($2)")
of mConStrStr: genConStrStr(p, n, r) of mConStrStr: genConStrStr(p, n, r)
of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)") 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]) appf(r.res, "Field$1: $2", [i.toRope, a.res])
r.res.app("}") 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) = proc genConv(p: var TProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange) var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].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: else:
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
if r.res == nil: InternalError(n.info, "convStrToCStr") if r.res == nil: InternalError(n.info, "convStrToCStr")
useMagic(p, "toEcmaStr") useMagic(p, "toJSStr")
r.res = ropef("toEcmaStr($1)", [r.res]) r.res = ropef("toJSStr($1)", [r.res])
proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) = proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) =
# we do an optimization here as this is likely to slow down # 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)) if a.com != nil: appf(r.com, "$1;$n", mergeStmt(a))
else: else:
genLineDir(p, n, r) genLineDir(p, n, r)
finishTryStmt(p, r, p.nestedTryStmts)
app(r.com, "break BeforeRet;" & tnl) app(r.com, "break BeforeRet;" & tnl)
proc genProcBody(p: var TProc, prc: PSym, r: TCompRes): PRope = 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 resultAsgn = nil
name = mangleName(prc) name = mangleName(prc)
header = generateHeader(p, prc.typ) 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 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))]) createVar(p, resultSym.typ, isIndirect(resultSym))])
gen(p, prc.ast.sons[resultPos], a) gen(p, prc.ast.sons[resultPos], a)
if a.com != nil: appf(returnStmt, "$1;$n", [a.com]) 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) genStmt(p, prc.getBody, r)
r.com = ropef("function $1($2) {$n$3$4$5}$n", r.com = ropef("function $#($#) {$n$#$#$#$#}$n",
[name, header, resultAsgn, genProcBody(p, prc, r), returnStmt]) [name, header, p.locals, resultAsgn,
genProcBody(p, prc, r), returnStmt])
r.res = nil r.res = nil
#if gVerbosity >= 3: #if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s # echo "END generated code for: " & prc.name.s
@ -1513,8 +1519,9 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkProcDef, nkMethodDef, nkConverterDef: of nkProcDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym var s = n.sons[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
var r2: TCompRes #var r2: TCompRes
genSym(p, n.sons[namePos], r2) genSym(p, n.sons[namePos], r)
r.res = nil
of nkGotoState, nkState: of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented") internalError(n.info, "first class iterators not implemented")
else: else:
@ -1566,6 +1573,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
of nkCurly: genSetConstr(p, n, r) of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r)
of nkPar: genTupleConstr(p, n, r) of nkPar: genTupleConstr(p, n, r)
of nkObjConstr: genObjConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr: genAddr(p, n, r) of nkAddr, nkHiddenAddr: genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(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") if m.module == nil: InternalError(n.info, "myProcess")
initProc(p, globals, m, nil, m.module.options) initProc(p, globals, m, nil, m.module.options)
genModule(p, n, r) genModule(p, n, r)
app(p.g.code, p.data) app(p.g.code, p.locals)
app(p.g.code, mergeStmt(r)) app(p.g.code, mergeStmt(r))
proc myClose(b: PPassContext, n: PNode): PNode = proc myClose(b: PPassContext, n: PNode): PNode =
@ -1660,10 +1668,10 @@ proc myClose(b: PPassContext, n: PNode): PNode =
discard writeRopeIfNotEqual(con(genHeader(), code), outfile) discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = 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 result = nil
proc myOpen(s: PSym): PPassContext = proc myOpen(s: PSym): PPassContext =
result = newModule(s) 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 # we cannot generate a proper thunk here for GC-safety reasons (see internal
# documentation): # documentation):
if gCmd == cmdCompileToEcmaScript: return prc if gCmd == cmdCompileToJS: return prc
result = newNodeIT(nkClosure, prc.info, dest) result = newNodeIT(nkClosure, prc.info, dest)
var conv = newNodeIT(nkHiddenStdConv, prc.info, dest) var conv = newNodeIT(nkHiddenStdConv, prc.info, dest)
conv.add(emptyNode) conv.add(emptyNode)
@ -391,7 +391,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
gatherVars(o, inner, body) gatherVars(o, inner, body)
# dummy closure param needed? # dummy closure param needed?
if inner.closureParam == nil and n.sym.typ.callConv == ccClosure: 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) dummyClosureParam(o, inner)
# only transform if it really needs a closure: # only transform if it really needs a closure:
if inner.closureParam != nil: if inner.closureParam != nil:
@ -443,10 +443,15 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
searchForInnerProcs(o, n.sons[i]) searchForInnerProcs(o, n.sons[i])
proc newAsgnStmt(le, ri: PNode): PNode = proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
result = newNodeI(nkFastAsgn, ri.info) # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
result.add(le) # mean to be able to capture string literals which have no GC header.
result.add(ri) # 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) = proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info) var vpart = newNodeI(nkIdentDefs, v.info)
@ -481,13 +486,13 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
if local.kind == skParam: if local.kind == skParam:
# maybe later: (sfByCopy in local.flags) # maybe later: (sfByCopy in local.flags)
# add ``env.param = param`` # add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local))) result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
IdNodeTablePut(o.localsToAccess, local, fieldAccess) IdNodeTablePut(o.localsToAccess, local, fieldAccess)
# add support for 'up' references: # add support for 'up' references:
for e, field in items(scope.deps): for e, field in items(scope.deps):
# add ``env.up = env2`` # add ``env.up = env2``
result.add(newAsgnStmt(indirectAccess(env, field, env.info), 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 = proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if n == nil: return nil if n == nil: return nil
@ -543,7 +548,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if x != nil: n.sons[i] = x if x != nil: n.sons[i] = x
proc liftLambdas*(fn: PSym, body: PNode): PNode = proc liftLambdas*(fn: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToEcmaScript: if body.kind == nkEmpty or gCmd == cmdCompileToJS:
# ignore forward declaration: # ignore forward declaration:
result = body result = body
else: else:
@ -566,7 +571,7 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
result = ex result = ex
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToEcmaScript: if body.kind == nkEmpty or gCmd == cmdCompileToJS:
result = body result = body
else: else:
var o = newOuterContext(module) 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. # DOS or Macintosh text files, even when it is not the native format.
import import
hashes, options, msgs, strutils, platform, idents, lexbase, llstream, hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg wordrecg
const const
@ -530,10 +530,10 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos] case L.buf[pos]
of CR: of CR:
registerLine() registerLine()
result = lexbase.HandleCR(L, pos) result = nimlexbase.HandleCR(L, pos)
of LF: of LF:
registerLine() registerLine()
result = lexbase.HandleLF(L, pos) result = nimlexbase.HandleLF(L, pos)
else: result = pos else: result = pos
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = 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) pos = HandleCRLF(L, pos)
buf = L.buf buf = L.buf
add(tok.literal, tnl) add(tok.literal, tnl)
of lexbase.EndOfFile: of nimlexbase.EndOfFile:
var line2 = L.linenumber var line2 = L.linenumber
L.LineNumber = line L.LineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart) lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
@ -581,7 +581,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
else: else:
inc(pos) # skip '"' inc(pos) # skip '"'
break break
elif c in {CR, LF, lexbase.EndOfFile}: elif c in {CR, LF, nimlexbase.EndOfFile}:
lexMessage(L, errClosingQuoteExpected) lexMessage(L, errClosingQuoteExpected)
break break
elif (c == '\\') and not rawMode: 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 # a comment ends if the next line does not start with the # on the same
# column after only whitespace # column after only whitespace
tok.tokType = tkComment tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
var col = getColNumber(L, pos) var col = getColNumber(L, pos)
while true: while true:
var lastBackslash = -1 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 if buf[pos] == '\\': lastBackslash = pos+1
add(tok.literal, buf[pos]) add(tok.literal, buf[pos])
inc(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 # a backslash is a continuation character if only followed by spaces
# plus a newline: # plus a newline:
while buf[lastBackslash] == ' ': inc(lastBackslash) while buf[lastBackslash] == ' ': inc(lastBackslash)
if buf[lastBackslash] notin {CR, LF, lexbase.EndOfFile}: if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
# false positive: # false positive:
lastBackslash = -1 lastBackslash = -1
@ -699,6 +701,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
if buf[pos] == '#' and (col == indent or lastBackslash > 0): if buf[pos] == '#' and (col == indent or lastBackslash > 0):
tok.literal.add "\n" tok.literal.add "\n"
col = indent col = indent
inc tok.iNumber
else: else:
if buf[pos] > ' ': if buf[pos] > ' ':
L.indentAhead = indent L.indentAhead = indent
@ -838,7 +841,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
else: else:
if c in OpChars: if c in OpChars:
getOperator(L, tok) getOperator(L, tok)
elif c == lexbase.EndOfFile: elif c == nimlexbase.EndOfFile:
tok.toktype = tkEof tok.toktype = tkEof
else: else:
tok.literal = c & "" 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 = proc getSysSym(name: string): PSym =
result = StrTableGet(systemModule.tab, getIdent(name)) 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) if result.kind == skStub: loadStub(result)
proc sysTypeFromName*(name: string): PType = proc sysTypeFromName*(name: string): PType =

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

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

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

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

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

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

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

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

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

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

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

@ -98,13 +98,13 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
result.typ = settype result.typ = settype
result.info = info result.info = info
e = 0 e = 0
while e < high(s) * elemSize: while e < len(s) * elemSize:
if bitSetIn(s, e): if bitSetIn(s, e):
a = e a = e
b = e b = e
while true: while true:
Inc(b) 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) Dec(b)
if a == b: if a == b:
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType)) addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))

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

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

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

View file

@ -187,21 +187,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
else: else:
result = arLValue result = arLValue
of nkDotExpr: 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 result = arLValue
else: else:
result = isAssignable(owner, n.sons[0]) result = isAssignable(owner, n.sons[0])
if result != arNone and sfDiscriminant in n.sons[1].sym.flags: if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
result = arDiscriminant result = arDiscriminant
of nkBracketExpr: 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 result = arLValue
else: else:
result = isAssignable(owner, n.sons[0]) result = isAssignable(owner, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
# Object and tuple conversions are still addressable, so we skip them # Object and tuple conversions are still addressable, so we skip them
# XXX why is 'tyOpenArray' allowed here? # 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]) result = isAssignable(owner, n.sons[1])
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct): elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
# types that are equal modulo distinction preserve l-value: # 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. # standard library.
import import
llstream, nhashes, strutils, lexbase llstream, nhashes, strutils, nimlexbase
type type
TCfgEventKind* = enum TCfgEventKind* = enum

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

@ -254,10 +254,16 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
optPar(p) optPar(p)
eat(p, endToken) eat(p, endToken)
proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode = proc exprColonEqExpr(p: var TParser): PNode =
var a = parseExpr(p) var a = parseExpr(p)
if p.tok.tokType == tok: if p.tok.tokType == tkColon:
result = newNodeP(kind, p) result = newNodeP(nkExprColonExpr, p)
getTok(p)
#optInd(p, result)
addSon(result, a)
addSon(result, parseExpr(p))
elif p.tok.tokType == tkEquals:
result = newNodeP(nkExprEqExpr, p)
getTok(p) getTok(p)
#optInd(p, result) #optInd(p, result)
addSon(result, a) addSon(result, a)
@ -309,14 +315,13 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
optInd(p, a) optInd(p, a)
eat(p, endTok) eat(p, endTok)
proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind, proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
endTok, sepTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and
(p.tok.tokType != tkSad) and (p.tok.tokType != tkInd): (p.tok.tokType != tkSad) and (p.tok.tokType != tkInd):
var a = exprColonEqExpr(p, elemKind, sepTok) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -324,10 +329,10 @@ proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind,
optPar(p) optPar(p)
eat(p, endTok) eat(p, endTok)
proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind, proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
endTok, sepTok: TTokType): PNode = endTok: TTokType): PNode =
result = newNodeP(kind, p) result = newNodeP(kind, p)
exprColonEqExprListAux(p, elemKind, endTok, sepTok, result) exprColonEqExprListAux(p, endTok, result)
proc setOrTableConstr(p: var TParser): PNode = proc setOrTableConstr(p: var TParser): PNode =
result = newNodeP(nkCurly, p) result = newNodeP(nkCurly, p)
@ -338,7 +343,7 @@ proc setOrTableConstr(p: var TParser): PNode =
result.kind = nkTableConstr result.kind = nkTableConstr
else: else:
while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}: 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 if a.kind == nkExprColonExpr: result.kind = nkTableConstr
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -473,14 +478,13 @@ proc identOrLiteral(p: var TParser): PNode =
getTok(p) getTok(p)
of tkParLe: of tkParLe:
# () constructor # () constructor
result = exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon) result = exprColonEqExprList(p, nkPar, tkParRi)
of tkCurlyLe: of tkCurlyLe:
# {} constructor # {} constructor
result = setOrTableConstr(p) result = setOrTableConstr(p)
of tkBracketLe: of tkBracketLe:
# [] constructor # [] constructor
result = exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi, result = exprColonEqExprList(p, nkBracket, tkBracketRi)
tkColon)
of tkCast: of tkCast:
result = parseCast(p) result = parseCast(p)
else: else:
@ -496,8 +500,11 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
var a = result var a = result
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
addSon(result, a) addSon(result, a)
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) exprColonEqExprListAux(p, tkParRi, result)
parseDoBlocks(p, result) if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
else:
parseDoBlocks(p, result)
of tkDo: of tkDo:
var a = result var a = result
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
@ -564,7 +571,7 @@ proc parsePragma(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and
(p.tok.tokType != tkEof) and (p.tok.tokType != tkSad): (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad):
var a = exprColonEqExpr(p, nkExprColonExpr, tkColon) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
getTok(p) getTok(p)
@ -739,7 +746,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
proc isExprStart(p: TParser): bool = proc isExprStart(p: TParser): bool =
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
tkProc, tkIterator, tkBind, tkProc, tkIterator, tkBind, tkAddr,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared: tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared:
result = true result = true
@ -1202,7 +1209,7 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
proc newCommentStmt(p: var TParser): PNode = proc newCommentStmt(p: var TParser): PNode =
result = newNodeP(nkCommentStmt, p) 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 type
TDefParser = proc (p: var TParser): PNode {.nimcall.} 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). # conditionals to condsyms (end of module).
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga, osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
osAtari, osNetware, osMacos, osMacosx, osHaiku, osEcmaScript, osNimrodVM, osAtari, osNetware, osMacos, osMacosx, osHaiku, osJS, osNimrodVM,
osStandalone osStandalone
type type
@ -136,7 +136,7 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "EcmaScript", parDir: "..", (name: "JS", parDir: "..",
dllFrmt: "lib$1.so", altDirSep: "/", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", objExt: ".o", newLine: "\x0A",
pathSep: ":", dirSep: "/", pathSep: ":", dirSep: "/",
@ -155,7 +155,7 @@ type
# alias conditionals to condsyms (end of module). # alias conditionals to condsyms (end of module).
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
cpuEcmaScript, cpuNimrodVM, cpuAVR cpuJS, cpuNimrodVM, cpuAVR
type type
TEndian* = enum TEndian* = enum
@ -177,7 +177,7 @@ const
(name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), (name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "arm", intSize: 32, endian: littleEndian, 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: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)] (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 = newLib(kind)
result.path = path result.path = path
Append(c.libs, result) Append(c.libs, result)
if path.kind in {nkStrLit..nkTripleStrLit}:
result.isOverriden = options.isDynLibOverride(path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode = proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr: if n.kind != nkExprColonExpr:
@ -225,8 +227,9 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
else: else:
if n.kind == nkExprColonExpr: if n.kind == nkExprColonExpr:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n)) var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
addToLib(lib, sym) if not lib.isOverriden:
incl(sym.loc.flags, lfDynamicLib) addToLib(lib, sym)
incl(sym.loc.flags, lfDynamicLib)
else: else:
incl(sym.loc.flags, lfExportLib) incl(sym.loc.flags, lfExportLib)
# since we'll be loading the dynlib symbols dynamically, we must use # since we'll be loading the dynlib symbols dynamically, we must use

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

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -14,10 +14,6 @@ import
ast, astalgo, msgs, semdata, types, trees ast, astalgo, msgs, semdata, types, trees
proc equalGenericParams(procA, procB: PNode): bool = 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 if sonsLen(procA) != sonsLen(procB): return
for i in countup(0, sonsLen(procA) - 1): for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym: if procA.sons[i].kind != nkSym:
@ -26,11 +22,11 @@ proc equalGenericParams(procA, procB: PNode): bool =
if procB.sons[i].kind != nkSym: if procB.sons[i].kind != nkSym:
InternalError(procB.info, "equalGenericParams") InternalError(procB.info, "equalGenericParams")
return return
a = procA.sons[i].sym let a = procA.sons[i].sym
b = procB.sons[i].sym let b = procB.sons[i].sym
if (a.name.id != b.name.id) or if a.name.id != b.name.id or
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
if (a.ast != nil) and (b.ast != nil): if a.ast != nil and b.ast != nil:
if not ExprStructuralEquivalent(a.ast, b.ast): return if not ExprStructuralEquivalent(a.ast, b.ast): return
result = true result = true
@ -39,10 +35,23 @@ proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym =
# the same the sym in the symbol table is returned, else nil. # the same the sym in the symbol table is returned, else nil.
var it: TIdentIter var it: TIdentIter
result = initIdentIter(it, c.tab.stack[tos], fn.Name) result = initIdentIter(it, c.tab.stack[tos], fn.Name)
while result != nil: if isGenericRoutine(fn):
if (result.Kind == fn.kind): # we simply check the AST; this is imprecise but nearly the best what
if equalGenericParams(result.ast.sons[genericParamsPos], # can be done; this doesn't work either though as type constraints are
fn.ast.sons[genericParamsPos]): # 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) case equalParams(result.typ.n, fn.typ.n)
of paramsEqual: of paramsEqual:
return return
@ -51,7 +60,7 @@ proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym =
return return
of paramsNotEqual: of paramsNotEqual:
nil nil
result = NextIdentIter(it, c.tab.stack[tos]) result = NextIdentIter(it, c.tab.stack[tos])
when false: when false:
proc paramsFitBorrow(child, parent: PNode): bool = 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)) else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n)) 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 result = lsub(n.sons[0]) + lcomma(n, 1) + 2
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1]) of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()") 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 nkRStrLit: put(g, tkRStrLit, atom(n))
of nkCharLit: put(g, tkCharLit, atom(n)) of nkCharLit: put(g, tkCharLit, atom(n))
of nkNilLit: put(g, tkNil, atom(n)) # complex expressions 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]) if sonsLen(n) >= 1: gsub(g, n.sons[0])
put(g, tkParLe, "(") put(g, tkParLe, "(")
gcomma(g, n, 1) gcomma(g, n, 1)

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

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -127,7 +127,7 @@ type
options: TOptions options: TOptions
reason: TReasonForRecompile reason: TReasonForRecompile
modDeps: seq[int32] modDeps: seq[int32]
files: TStringSeq files: seq[int32]
dataIdx: int # offset of start of data section dataIdx: int # offset of start of data section
convertersIdx: int # offset of start of converters section convertersIdx: int # offset of start of converters section
initIdx, interfIdx, compilerProcsIdx, methodsIdx: int initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
@ -140,6 +140,7 @@ type
memfile: TMemFile # unfortunately there is no point in time where we memfile: TMemFile # unfortunately there is no point in time where we
# can close this! XXX # can close this! XXX
methods*: TSymSeq methods*: TSymSeq
inViewMode: bool
PRodReader* = ref TRodReader PRodReader* = ref TRodReader
@ -381,8 +382,14 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
result.id = id result.id = id
IdTablePut(r.syms, result, result) IdTablePut(r.syms, result, result)
if debugIds: registerID(result) if debugIds: registerID(result)
elif (result.id != id): elif result.id != id:
InternalError(info, "decodeSym: wrong 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.kind = k
result.name = ident # read the rest of the symbol description: result.name = ident # read the rest of the symbol description:
if r.s[r.pos] == '^': if r.s[r.pos] == '^':
@ -495,7 +502,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
IdTablePut(r.syms, s, s) IdTablePut(r.syms, s, s)
StrTableAdd(rodCompilerProcs, 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 var key, val, tmp: int
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
@ -509,6 +516,7 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
key = idx.lastIdxKey + 1 key = idx.lastIdxKey + 1
val = tmp + idx.lastIdxVal val = tmp + idx.lastIdxVal
IITablePut(idx.tab, key, val) IITablePut(idx.tab, key, val)
if not outf.isNil: outf.write(key, " ", val, "\n")
idx.lastIdxKey = key idx.lastIdxKey = key
idx.lastIdxVal = val idx.lastIdxVal = val
setID(key) # ensure that this id will not be used 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 :-) # new command forces us to consider it here :-)
case old case old
of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToEcmaScript, cmdCompileToLLVM: cmdCompileToJS, cmdCompileToLLVM:
if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef, if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
cmdInteractive}: cmdInteractive}:
return false return false
@ -576,9 +584,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
while r.s[r.pos] != ')': while r.s[r.pos] != ')':
var relativePath = decodeStr(r.s, r.pos) let relativePath = decodeStr(r.s, r.pos)
var resolvedPath = relativePath.findModule let resolvedPath = relativePath.findModule
r.files.add(if resolvedPath.len > 0: resolvedPath else: relativePath) let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
inc(r.pos) # skip #10 inc(r.pos) # skip #10
inc(r.line) inc(r.line)
if r.s[r.pos] == ')': inc(r.pos) 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.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
while r.s[r.pos] != ')': 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 ' ' inc(r.pos) # skip ' '
inclCrc = decodeVInt(r.s, r.pos) inclCrc = decodeVInt(r.s, r.pos)
if r.reason == rrNone: if r.reason == rrNone:
@ -599,7 +608,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
of "DEPS": of "DEPS":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
r.modDeps.add int32(decodeVInt(r.s, r.pos)) r.modDeps.add(r.files[int32(decodeVInt(r.s, r.pos))])
if r.s[r.pos] == ' ': inc(r.pos) if r.s[r.pos] == ' ': inc(r.pos)
of "INTERF": of "INTERF":
r.interfIdx = r.pos + 2 r.interfIdx = r.pos + 2
@ -670,11 +679,9 @@ proc newRodReader(modfilename: string, crc: TCrc32,
add(version, r.s[r.pos]) add(version, r.s[r.pos])
inc(r.pos) inc(r.pos)
if r.s[r.pos] == '\x0A': 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 # since ROD files are only for caching, no backwards compatibility is
# needed # needed
processRodFile(r, crc)
else:
result = nil result = nil
else: else:
result = nil result = nil
@ -719,8 +726,14 @@ proc findSomeWhere(id: int) =
echo "found id ", id, " in ", gMods[i].filename echo "found id ", id, " in ", gMods[i].filename
proc getReader(moduleId: int): PRodReader = proc getReader(moduleId: int): PRodReader =
InternalAssert moduleId >= 0 and moduleId < gMods.len # we can't index 'gMods' here as it's indexed by a *file index* which is not
result = gMods[moduleId].rd # 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 = proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
result = PSym(IdTableGet(r.syms, id)) result = PSym(IdTableGet(r.syms, id))
@ -810,6 +823,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
if r == nil: if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else: else:
processRodFile(r, crc)
result = r.reason result = r.reason
if result == rrNone: if result == rrNone:
# check modules it depends on # check modules it depends on
@ -860,6 +874,8 @@ proc rawLoadStub(s: PSym) =
if d == invalidKey: InternalError("loadStub: invalid key") if d == invalidKey: InternalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, UnknownLineInfo()) 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") InternalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId: elif rs.id != theId:
InternalError(rs.info, "loadStub: wrong ID") InternalError(rs.info, "loadStub: wrong ID")
@ -894,3 +910,264 @@ proc getBody*(s: PSym): PNode =
InitIdTable(gTypeTable) InitIdTable(gTypeTable)
InitStrTable(rodCompilerProcs) 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 return
# we need no surrounding [] here because the type is in a line of its own # we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: InternalError("encodeType: tyForward") 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) encodeVInt(ord(t.kind), result)
add(result, '+') add(result, '+')
encodeVInt(t.id, 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 # implementation
type proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
TExprFlag = enum proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType procvar.}
TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprNoType(c: PContext, n: PNode): PNode proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: 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 semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
@ -200,14 +196,12 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast) addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len c.lastGenericIdx = c.generics.len
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
result = semExpr(c, n, {})
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =
var c = newContext(module) var c = newContext(module)
if c.p != nil: InternalError(module.info, "sem.myOpen") if c.p != nil: InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
c.semExpr = semExprNoFlags c.semExpr = semExpr
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall c.semOverloadedCall = semOverloadedCall
c.semTypeNode = semTypeNode 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) #writeMatches(alt)
if c.inCompilesContext > 0: if c.inCompilesContext > 0:
# quick error message for performance of 'compiles' built-in: # quick error message for performance of 'compiles' built-in:
GlobalError(n.Info, errAmbiguousCallXYZ, "") GlobalError(n.Info, errGenerated, "ambiguous call")
elif gErrorCounter == 0: elif gErrorCounter == 0:
# don't cascade errors # don't cascade errors
var args = "(" var args = "("
@ -174,7 +174,10 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# common case; check the only candidate has the right # common case; check the only candidate has the right
# number of generic type parameters: # number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1: 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) result = explicitGenericSym(c, n, s)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}: elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters. # 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)) call.add(newIdentNode(fn.name, fn.info))
for i in 1.. <fn.typ.n.len: for i in 1.. <fn.typ.n.len:
let param = fn.typ.n.sons[i] 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)) call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
var resolved = semOverloadedCall(c, call, call, {fn.kind}) var resolved = semOverloadedCall(c, call, call, {fn.kind})
if resolved != nil: if resolved != nil:

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

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

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

@ -10,18 +10,6 @@
# this module does the semantic checking for expressions # this module does the semantic checking for expressions
# included from sem.nim # 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 = proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s) markUsed(n, s)
pushInfoContext(n.info) pushInfoContext(n.info)
@ -31,9 +19,38 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc newDeref(n: PNode): PNode {.inline.} = proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0]) var smoduleId = getModule(s).id
addSon(result, n) 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 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:
# XXX tyGenericInst here?
if result.typ.kind == tyVar: result = newDeref(result)
else:
LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags) result = semExpr(c, n, flags)
@ -42,7 +59,10 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
#raiseRecoverableError("") #raiseRecoverableError("")
result = errorNode(c, n) result = errorNode(c, n)
if result.typ != nil: if result.typ != nil:
# XXX tyGenericInst here?
semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
semDestructorCheck(c, result, flags)
else: else:
LocalError(n.info, errExprXHasNoType, LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
@ -57,6 +77,9 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
LocalError(n.info, errExprXHasNoType, LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
result.typ = errorType(c) result.typ = errorType(c)
else:
semProcvarCheck(c, result)
semDestructorCheck(c, result, flags)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
@ -66,20 +89,11 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result.typ = s.typ result.typ = s.typ
result.info = n.info 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 = proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind case s.kind
of skConst: of skConst:
markUsed(n, s) markUsed(n, s)
case skipTypes(s.typ, abstractInst).kind case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64: tyTuple, tySet, tyUInt..tyUInt64:
result = inlineConst(n, s) result = inlineConst(n, s)
@ -149,7 +163,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
result = convNotNeedeed result = convNotNeedeed
return return
var d = skipTypes(castDest, abstractVar) 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): while (d != nil) and (d.Kind in {tyPtr, tyRef}) and (d.Kind == s.Kind):
d = base(d) d = base(d)
s = base(s) s = base(s)
@ -158,7 +172,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
elif d.Kind == tyObject and s.Kind == tyObject: elif d.Kind == tyObject and s.Kind == tyObject:
result = checkConversionBetweenObjects(d, s) result = checkConversionBetweenObjects(d, s)
elif (skipTypes(castDest, abstractVarRange).Kind in IntegralTypes) and 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 # accept conversion between integral types
else: else:
# we use d, s here to speed up that operation a bit: # we use d, s here to speed up that operation a bit:
@ -185,7 +199,7 @@ proc isCastable(dst, src: PType): bool =
else: else:
result = (ds >= ss) or result = (ds >= ss) or
(skipTypes(dst, abstractInst).kind in IntegralTypes) 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.} = proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices result = n.kind in nkSymChoices
@ -238,15 +252,15 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
LocalError(n.info, errXExpectsTypeOrValue, opToStr[m]) LocalError(n.info, errXExpectsTypeOrValue, opToStr[m])
else: else:
n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
var typ = skipTypes(n.sons[1].typ, abstractVarRange) var typ = skipTypes(n.sons[1].typ, abstractVarRange)
case typ.Kind case typ.Kind
of tySequence, tyString, tyOpenArray, tyVarargs: of tySequence, tyString, tyOpenArray, tyVarargs:
n.typ = getSysType(tyInt) n.typ = getSysType(tyInt)
of tyArrayConstr, tyArray: 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: 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]) else: LocalError(n.info, errInvalidArgForX, opToStr[m])
result = n result = n
@ -255,7 +269,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
LocalError(n.info, errXExpectsTypeOrValue, "sizeof") LocalError(n.info, errXExpectsTypeOrValue, "sizeof")
else: else:
n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1]) #restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt) n.typ = getSysType(tyInt)
result = n result = n
@ -265,10 +279,10 @@ proc semOf(c: PContext, n: PNode): PNode =
n.sons[2] = semExprWithType(c, n.sons[2]) n.sons[2] = semExprWithType(c, n.sons[2])
#restoreOldStyleType(n.sons[1]) #restoreOldStyleType(n.sons[1])
#restoreOldStyleType(n.sons[2]) #restoreOldStyleType(n.sons[2])
let a = skipTypes(n.sons[1].typ, typedescPtrs) let a = skipTypes(n.sons[1].typ, abstractPtrs)
let b = skipTypes(n.sons[2].typ, typedescPtrs) let b = skipTypes(n.sons[2].typ, abstractPtrs)
let x = skipTypes(n.sons[1].typ, abstractPtrs) let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
let y = skipTypes(n.sons[2].typ, abstractPtrs) let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
if x.kind == tyTypeDesc or y.kind != tyTypeDesc: if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
LocalError(n.info, errXExpectsObjectTypes, "of") LocalError(n.info, errXExpectsObjectTypes, "of")
@ -319,7 +333,7 @@ proc semIs(c: PContext, n: PNode): PNode =
proc semOpAux(c: PContext, n: PNode) = proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType} const flags = {efDetermineType}
for i in countup(1, n.sonsLen- 1): for i in countup(1, n.sonsLen-1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info var info = a.sons[0].info
@ -340,11 +354,11 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i]) for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
result = semExpr(c, result) result = semExpr(c, result)
proc changeType(n: PNode, newType: PType) = proc changeType(n: PNode, newType: PType, check: bool) =
case n.kind case n.kind
of nkCurly, nkBracket: of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType)) changeType(n.sons[i], elemType(newType), check)
of nkPar: of nkPar:
if newType.kind != tyTuple: if newType.kind != tyTuple:
InternalError(n.info, "changeType: no tuple type for constructor") InternalError(n.info, "changeType: no tuple type for constructor")
@ -359,15 +373,21 @@ proc changeType(n: PNode, newType: PType) =
if f == nil: if f == nil:
internalError(m.info, "changeType(): invalid identifier") internalError(m.info, "changeType(): invalid identifier")
return return
changeType(n.sons[i].sons[1], f.typ) changeType(n.sons[i].sons[1], f.typ, check)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i] var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym)) addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m) addSon(a, m)
changeType(m, newType.sons[i]) changeType(m, newType.sons[i], check)
n.sons[i] = a 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 else: nil
n.typ = newType n.typ = newType
@ -384,7 +404,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info) typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
result = typ result = typ
proc semArrayConstr(c: PContext, n: PNode): PNode = proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newNodeI(nkBracket, n.info) result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArrayConstr, c) result.typ = newTypeS(tyArrayConstr, c)
rawAddSon(result.typ, nil) # index type rawAddSon(result.typ, nil) # index type
@ -413,7 +433,7 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
localError(x.info, errInvalidOrderInArrayConstructor) localError(x.info, errInvalidOrderInArrayConstructor)
x = x.sons[1] 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])) addSon(result, fitNode(c, typ, n.sons[i]))
inc(lastIndex) inc(lastIndex)
addSonSkipIntLit(result.typ, typ) addSonSkipIntLit(result.typ, typ)
@ -447,11 +467,11 @@ proc fixAbstractType(c: PContext, n: PNode) =
elif skipTypes(it.sons[1].typ, abstractVar).kind in elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}: {tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar) var s = skipTypes(it.typ, abstractVar)
changeType(it.sons[1], s) changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1] n.sons[i] = it.sons[1]
of nkBracket: of nkBracket:
# an implicitely constructed array (passed to an open array): # an implicitely constructed array (passed to an open array):
n.sons[i] = semArrayConstr(c, it) n.sons[i] = semArrayConstr(c, it, {})
else: else:
nil nil
#if (it.typ == nil): #if (it.typ == nil):
@ -485,7 +505,8 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
case n.kind case n.kind
of nkSym: of nkSym:
# n.sym.typ can be nil in 'check' mode ... # 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) incl(n.sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n) result = newHiddenAddrTaken(c, n)
of nkDotExpr: of nkDotExpr:
@ -493,16 +514,16 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
if n.sons[1].kind != nkSym: if n.sons[1].kind != nkSym:
internalError(n.info, "analyseIfAddressTaken") internalError(n.info, "analyseIfAddressTaken")
return 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) incl(n.sons[1].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n) result = newHiddenAddrTaken(c, n)
of nkBracketExpr: of nkBracketExpr:
checkMinSonsLen(n, 1) 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) if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n) result = newHiddenAddrTaken(c, n)
else: else:
result = newHiddenAddrTaken(c, n) # BUGFIX! result = newHiddenAddrTaken(c, n)
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
checkMinSonsLen(n, 1) 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: 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! # 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): for i in countup(1, sonsLen(n) - 1):
if i < sonsLen(t) and t.sons[i] != nil and 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}: 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 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 if i < sonsLen(t) and
skipTypes(t.sons[i], abstractInst).kind == tyVar: skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
n.sons[i] = analyseIfAddressTaken(c, n.sons[i]) if n.sons[i].kind != nkHiddenAddr:
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
include semmagic include semmagic
@ -541,11 +570,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
call.add(n.sons[0]) call.add(n.sons[0])
var allConst = true var allConst = true
for i in 1 .. < n.len: for i in 1 .. < n.len:
let a = getConstExpr(c.module, n.sons[i]) var a = getConstExpr(c.module, n.sons[i])
if a != nil: call.add(a) if a == nil:
else:
allConst = false allConst = false
call.add(n.sons[i]) a = n.sons[i]
if a.kind == nkHiddenStdConv: a = a.sons[1]
call.add(a)
if allConst: if allConst:
result = semfold.getConstExpr(c.module, call) result = semfold.getConstExpr(c.module, call)
if result.isNil: result = n if result.isNil: result = n
@ -617,6 +647,7 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil result = nil
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -635,8 +666,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let nOrig = n.copyTree let nOrig = n.copyTree
semOpAux(c, n) semOpAux(c, n)
var t: PType = nil var t: PType = nil
if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst) if n.sons[0].typ != nil:
if (t != nil) and (t.kind == tyProc): t = skipTypes(n.sons[0].typ, abstractInst-{tyTypedesc})
if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution # This is a proc variable, apply normal overload resolution
var m: TCandidate var m: TCandidate
initCandidate(m, t) initCandidate(m, t)
@ -668,7 +700,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we assume that a procedure that calls something indirectly # we assume that a procedure that calls something indirectly
# has side-effects: # has side-effects:
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect) 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}) let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
result = semConv(c, n, symFromType(destType, n.info)) result = semConv(c, n, symFromType(destType, n.info))
return return
@ -694,7 +727,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(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! # this seems to be a hotspot in the compiler!
let nOrig = n.copyTree let nOrig = n.copyTree
semOpAux(c, n) #semLazyOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil: if result == nil:
result = overloadedCallOpr(c, n) 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 skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, result, callee) of skTemplate: result = semTemplateExpr(c, result, callee)
else: else:
semFinishOperands(c, n)
activate(c, n) activate(c, n)
fixAbstractType(c, result) fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result) analyseIfAddressTakenInCall(c, result)
@ -714,7 +748,8 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = evalAtCompileTime(c, result) result = evalAtCompileTime(c, result)
proc buildStringify(c: PContext, arg: PNode): PNode = 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 result = arg
else: else:
result = newNodeI(nkCall, arg.info) result = newNodeI(nkCall, arg.info)
@ -752,7 +787,7 @@ proc discardCheck(result: PNode) =
# XXX too much work and fixing would break bootstrapping: # XXX too much work and fixing would break bootstrapping:
#Message(n.info, warnNilStatement) #Message(n.info, warnNilStatement)
result.typ = nil 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: gCmd != cmdInteractive:
localError(result.info, errDiscardValue) localError(result.info, errDiscardValue)
@ -845,12 +880,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semSym(c, n, s, flags) return semSym(c, n, s, flags)
n.sons[0] = semExprWithType(c, n.sons[0], 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 i = considerAcc(n.sons[1])
var ty = n.sons[0].typ var ty = n.sons[0].typ
var f: PSym = nil var f: PSym = nil
result = 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 case ty.kind
of tyEnum: of tyEnum:
# look up if the identifier belongs to the enum: # look up if the identifier belongs to the enum:
@ -971,7 +1007,8 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
checkSonsLen(n, 2) checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
for i in countup(1, sonsLen(n) - 1): 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 indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
if arg != nil: if arg != nil:
@ -1082,11 +1119,13 @@ proc semAsgn(c: PContext, n: PNode): PNode =
localError(a.info, errXCannotBeAssignedTo, localError(a.info, errXCannotBeAssignedTo,
renderTree(a, {renderNoComments})) renderTree(a, {renderNoComments}))
else: else:
var let
rhs = semExprWithType(c, n.sons[1])
lhs = n.sons[0] lhs = n.sons[0]
if lhs.kind == nkSym and lhs.sym.kind == skResult and lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
lhs.sym.typ.kind == tyGenericParam: 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): if matchTypeClass(lhs.typ, rhs.typ):
InternalAssert c.p.resultSym != nil InternalAssert c.p.resultSym != nil
lhs.typ = rhs.typ lhs.typ = rhs.typ
@ -1128,7 +1167,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
# ``result``: # ``result``:
if result.kind == nkSym and result.sym == c.p.resultSym: if result.kind == nkSym and result.sym == c.p.resultSym:
nil 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, # intended semantic: if it's 'discardable' and the context allows for it,
# discard it. This is bad for chaining but nicer for C wrappers. # discard it. This is bad for chaining but nicer for C wrappers.
# ambiguous :-( # ambiguous :-(
@ -1531,7 +1570,7 @@ proc checkPar(n: PNode): TParKind =
LocalError(n.sons[i].info, errNamedExprNotAllowed) LocalError(n.sons[i].info, errNamedExprNotAllowed)
return paNone return paNone
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode = proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newNodeI(nkPar, n.info) result = newNodeI(nkPar, n.info)
var typ = newTypeS(tyTuple, c) var typ = newTypeS(tyTuple, c)
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
@ -1545,7 +1584,8 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
else: id = n.sons[i].sons[0].sym.name else: id = n.sons[i].sons[0].sym.name
if ContainsOrIncl(ids, id.id): if ContainsOrIncl(ids, id.id):
localError(n.sons[i].info, errFieldInitTwice, id.s) 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) var f = newSymS(skField, n.sons[i].sons[0], c)
f.typ = skipIntLit(n.sons[i].sons[1].typ) f.typ = skipIntLit(n.sons[i].sons[1].typ)
rawAddSon(typ, f.typ) rawAddSon(typ, f.typ)
@ -1554,14 +1594,56 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
addSon(result, n.sons[i]) addSon(result, n.sons[i])
result.typ = typ 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: result = n # we don't modify n, but compute the type:
var typ = newTypeS(tyTuple, c) # leave typ.n nil! var typ = newTypeS(tyTuple, c) # leave typ.n nil!
for i in countup(0, sonsLen(n) - 1): 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) addSonSkipIntLit(typ, n.sons[i].typ)
result.typ = 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 = proc semStmtListExpr(c: PContext, n: PNode): PNode =
result = n result = n
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -1655,7 +1737,7 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
proc fixImmediateParams(n: PNode): PNode = proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out # XXX: Temporary work-around until we carry out
# the planned overload resolution reforms # 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] if n[i].kind == nkDo: n.sons[i] = n[i][bodyPos]
result = n result = n
@ -1690,7 +1772,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
semCaptureSym(s, c.p.owner) semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags) result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skIterator, skConverter}: if s.kind in {skProc, skMethod, skIterator, skConverter}:
performProcvarCheck(c, n, s) #performProcvarCheck(c, n, s)
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
if result.kind == nkSym: if result.kind == nkSym:
markIndirect(c, result.sym) markIndirect(c, result.sym)
@ -1769,6 +1851,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: if n.len == 2:
result = semConv(c, n, s) result = semConv(c, n, s)
elif n.len == 1:
result = semObjConstr(c, n, flags)
elif Contains(c.AmbiguousSymbols, s.id): elif Contains(c.AmbiguousSymbols, s.id):
LocalError(n.info, errUseQualifier, s.name.s) LocalError(n.info, errUseQualifier, s.name.s)
elif s.magic == mNone: result = semDirectOp(c, n, flags) elif s.magic == mNone: result = semDirectOp(c, n, flags)
@ -1807,11 +1891,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkPar: of nkPar:
case checkPar(n) case checkPar(n)
of paNone: result = errorNode(c, n) of paNone: result = errorNode(c, n)
of paTuplePositions: result = semTuplePositionsConstr(c, n) of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
of paTupleFields: result = semTupleFieldsConstr(c, n) of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
of paSingle: result = semExpr(c, n.sons[0], flags) of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n) 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 nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n) of nkDerefExpr: result = semDeref(c, n)
of nkAddr: of nkAddr:

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

@ -458,16 +458,23 @@ proc getAppType(n: PNode): PNode =
else: else:
result = newStrNodeT("console", n) 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? # XXX range checks?
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64: of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind 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) of tyChar: result = newIntNodeT(getOrdValue(a), n)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check: rangeCheck(n, result.intVal)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
@ -490,7 +497,7 @@ proc getArrayConstr(m: PSym, n: PNode): PNode =
proc foldArrayAccess(m: PSym, n: PNode): PNode = proc foldArrayAccess(m: PSym, n: PNode): PNode =
var x = getConstExpr(m, n.sons[0]) 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]) var y = getConstExpr(m, n.sons[1])
if y == nil: return if y == nil: return
@ -519,10 +526,10 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
proc foldFieldAccess(m: PSym, n: PNode): PNode = proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed # a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0]) 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 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] var it = x.sons[i]
if it.kind != nkExprColonExpr: if it.kind != nkExprColonExpr:
# lookup per index: # lookup per index:
@ -542,6 +549,11 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
if a == nil: return nil if a == nil: return nil
result.strVal.add(getStrOrChar(a)) 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 = proc getConstExpr(m: PSym, n: PNode): PNode =
result = nil result = nil
case n.kind case n.kind
@ -569,6 +581,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if sfFakeConst notin s.flags: result = copyTree(s.ast) if sfFakeConst notin s.flags: result = copyTree(s.ast)
elif s.kind in {skProc, skMethod}: # BUGFIX elif s.kind in {skProc, skMethod}: # BUGFIX
result = n result = n
elif s.kind in {skType, skGenericParam}:
result = newSymNodeTypeDesc(s, n.info)
of nkCharLit..nkNilLit: of nkCharLit..nkNilLit:
result = copyNode(n) result = copyNode(n)
of nkIfExpr: of nkIfExpr:
@ -587,11 +601,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined, LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof") "sizeof")
result = nil 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 result = nil
# XXX: size computation for complex types is still wrong # XXX: size computation for complex types is still wrong
else:
result = newIntNodeT(getSize(a.typ), n)
of mLow: of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n) result = newIntNodeT(firstOrd(n.sons[1].typ), n)
of mHigh: of mHigh:
@ -647,6 +663,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
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: of nkPar:
# tuple constructor # tuple constructor
result = copyTree(n) result = copyTree(n)
@ -679,7 +702,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1])
if a == nil: return if a == nil: return
result = foldConv(n, a) result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
of nkBracketExpr: result = foldArrayAccess(m, n) of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n) of nkDotExpr: result = foldFieldAccess(m, n)
else: else:

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

@ -63,12 +63,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
else: else:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skGenericParam: of skGenericParam:
result = newSymNode(s, n.info) result = newSymNodeTypeDesc(s, n.info)
of skParam: of skParam:
result = n result = n
of skType: of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNode(s, n.info) result = newSymNodeTypeDesc(s, n.info)
else: else:
result = n result = n
else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info)
@ -157,12 +157,12 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[0] = symChoice(c, n.sons[0], s, scOption) result.sons[0] = symChoice(c, n.sons[0], s, scOption)
first = 1 first = 1
of skGenericParam: of skGenericParam:
result.sons[0] = newSymNode(s, n.sons[0].info) result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
first = 1 first = 1
of skType: of skType:
# bad hack for generics: # bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): 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 first = 1
else: else:
result.sons[0] = newSymNode(s, n.sons[0].info) 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 # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -23,9 +23,10 @@ proc expectIntLit(c: PContext, n: PNode): int =
proc semInstantiationInfo(c: PContext, n: PNode): PNode = proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkPar, n.info, n.typ) result = newNodeIT(nkPar, n.info, n.typ)
let idx = expectIntLit(c, n.sons[1]) let idx = expectIntLit(c, n.sons[1])
let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx) let info = getInfoContext(idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString)) 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)) var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
line.intVal = ToLinenumber(info) line.intVal = ToLinenumber(info)
result.add(filename) result.add(filename)
@ -73,6 +74,33 @@ proc semBindSym(c: PContext, n: PNode): PNode =
else: else:
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal) 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 semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
proc magicsAfterOverloadResolution(c: PContext, n: PNode, proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
@ -86,5 +114,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mOrd: result = semOrd(c, n) of mOrd: result = semOrd(c, n)
of mShallowCopy: result = semShallowCopy(c, n, flags) of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n) of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n)
else: result = n else: result = n

View file

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

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

@ -119,11 +119,11 @@ proc semWhile(c: PContext, n: PNode): PNode =
closeScope(c.tab) closeScope(c.tab)
proc toCover(t: PType): biggestInt = proc toCover(t: PType): biggestInt =
var t2 = skipTypes(t, abstractVarRange) var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2): if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n) result = sonsLen(t2.n)
else: else:
result = lengthOrd(skipTypes(t, abstractVar)) result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
proc semCase(c: PContext, n: PNode): PNode = proc semCase(c: PContext, n: PNode): PNode =
# check selector: # check selector:
@ -133,7 +133,7 @@ proc semCase(c: PContext, n: PNode): PNode =
n.sons[0] = semExprWithType(c, n.sons[0]) n.sons[0] = semExprWithType(c, n.sons[0])
var chckCovered = false var chckCovered = false
var covered: biggestint = 0 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: of tyInt..tyInt64, tyChar, tyEnum:
chckCovered = true chckCovered = true
of tyFloat..tyFloat128, tyString, tyError: 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 = proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
result = fitNode(c, typ, n) result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ) changeType(result.sons[1], typ, check=true)
result = result.sons[1] result = result.sons[1]
elif not sameType(result.typ, typ): elif not sameType(result.typ, typ):
changeType(result, typ) changeType(result, typ, check=false)
proc findShadowedVar(c: PContext, v: PSym): PSym = proc findShadowedVar(c: PContext, v: PSym): PSym =
for i in countdown(c.tab.tos - 2, ModuleTablePos+1): for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
@ -207,7 +207,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
typ = nil typ = nil
var def: PNode var def: PNode
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1]) def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
# BUGFIX: ``fitNode`` is needed here! # BUGFIX: ``fitNode`` is needed here!
# check type compability between def.typ and typ: # check type compability between def.typ and typ:
if typ != nil: def = fitNode(c, typ, def) if typ != nil: def = fitNode(c, typ, def)
@ -301,52 +301,109 @@ proc semConst(c: PContext, n: PNode): PNode =
addSon(b, copyTree(def)) addSon(b, copyTree(def))
addSon(result, b) addSon(result, b)
proc transfFieldLoopBody(n: PNode, forLoop: PNode, type
tupleType: PType, TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
tupleIndex, first: int): PNode = 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 case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent: of nkIdent:
result = n result = n
var L = sonsLen(forLoop) var L = sonsLen(forLoop)
# field name: if c.replaceByFieldName:
if first > 0:
if n.ident.id == forLoop[0].ident.id: if n.ident.id == forLoop[0].ident.id:
if tupleType.n == nil: let fieldName = if c.tupleType.isNil: c.field.name.s
# ugh, there are no field names: elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
result = newStrNode(nkStrLit, "") else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
else: result = newStrNode(nkStrLit, fieldName)
result = newStrNode(nkStrLit, tupleType.n.sons[tupleIndex].sym.name.s)
return return
# other fields: # other fields:
for i in first..L-3: for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id: if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2] var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-first] var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
result = newNodeI(nkBracketExpr, n.info) if c.field.isNil:
result.add(tupl) result = newNodeI(nkBracketExpr, n.info)
result.add(newIntNode(nkIntLit, tupleIndex)) 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 break
else: else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n) result = copyNode(n)
newSons(result, sonsLen(n)) newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
result.sons[i] = transfFieldLoopBody(n.sons[i], forLoop, result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
tupleType, tupleIndex, first)
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 = proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce # so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ... # 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") var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
if trueSymbol == nil: if trueSymbol == nil:
LocalError(n.info, errSystemNeeds, "true") LocalError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool) trueSymbol.typ = getSysType(tyBool)
result.add(newSymNode(trueSymbol, n.info)) result.sons[0] = newSymNode(trueSymbol, n.info)
var stmts = newNodeI(nkStmtList, n.info) var stmts = newNodeI(nkStmtList, n.info)
result.add(stmts) result.sons[1] = stmts
var length = sonsLen(n) var length = sonsLen(n)
var call = n.sons[length-2] var call = n.sons[length-2]
@ -354,23 +411,34 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
LocalError(n.info, errWrongNumberOfVariables) LocalError(n.info, errWrongNumberOfVariables)
return result return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar) var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
if tupleTypeA.kind != tyTuple: InternalError(n.info, "no tuple type!") if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1: 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): if not SameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB) typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
Inc(c.p.nestedLoopCounter) Inc(c.p.nestedLoopCounter)
var loopBody = n.sons[length-1] if tupleTypeA.kind == tyTuple:
for i in 0..sonsLen(tupleTypeA)-1: var loopBody = n.sons[length-1]
openScope(c.tab) for i in 0..sonsLen(tupleTypeA)-1:
var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i, openScope(c.tab)
ord(m==mFieldPairs)) var fc: TFieldInstCtx
inc c.InUnrolledContext fc.tupleType = tupleTypeA
stmts.add(SemStmt(c, body)) fc.tupleIndex = i
dec c.InUnrolledContext fc.replaceByFieldName = m == mFieldPairs
closeScope(c.tab) 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) Dec(c.p.nestedLoopCounter)
var b = newNodeI(nkBreakStmt, n.info) var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode) 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]) n.sons[length-1] = SemStmt(c, n.sons[length-1])
Dec(c.p.nestedLoopCounter) 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 = proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
result = newNodeI(nkCall, arg.info) result = newNodeI(nkCall, arg.info)
result.add(newIdentNode(it.getIdent, 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}) result = semExprNoDeref(c, result, {efWantIterator})
proc semFor(c: PContext, n: PNode): PNode = 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 # XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned. # forward declarations. stay tuned.
when false: when false:
# well for now it breaks code ... I added the test case in main.nim of the # well for now it breaks code ...
# compiler itself to break bootstrapping :P
case n.kind case n.kind
of nkLambdaKinds: of nkLambdaKinds:
discard semLambda(c, n, {}) discard semLambda(c, n, {})
@ -994,7 +1068,7 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
result = nil result = nil
proc generateDestructor(c: PContext, t: PType): PNode = 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 ## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt = template addLine(e: expr): stmt =
@ -1029,7 +1103,7 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
if t.destructor != nil: if t.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need # 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] return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
case t.kind case t.kind
@ -1071,8 +1145,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
else: else:
return false return false
proc insertDestructors(c: PContext, varSection: PNode): proc insertDestructors(c: PContext,
tuple[outer: PNode, inner: PNode] = varSection: PNode): tuple[outer, inner: PNode] =
# Accepts a var or let section. # Accepts a var or let section.
# #
# When a var section has variables with destructors # When a var section has variables with destructors
@ -1128,7 +1202,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
return return
proc ImplicitelyDiscardable(n: PNode): bool = proc ImplicitlyDiscardable(n: PNode): bool =
result = isCallExpr(n) and n.sons[0].kind == nkSym and result = isCallExpr(n) and n.sons[0].kind == nkSym and
sfDiscardable in n.sons[0].sym.flags 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': # a statement list (s; e) has the type 'e':
if result.kind == nkStmtList and result.len > 0: if result.kind == nkStmtList and result.len > 0:
var lastStmt = lastSon(result) var lastStmt = lastSon(result)
if lastStmt.kind != nkNilLit and not ImplicitelyDiscardable(lastStmt): if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt):
result.typ = lastStmt.typ result.typ = lastStmt.typ
#localError(lastStmt.info, errGenerated, #localError(lastStmt.info, errGenerated,
# "Last expression must be explicitly returned if it " & # "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: # container construction:
result = toNil # nothing until later result = toNil # nothing until later
for i in 0..n.len-1: aggregateOwner(result, analyse(c, n[i])) 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: of nkAddr, nkHiddenAddr:
var a = lvalueSym(n) var a = lvalueSym(n)
if a.kind == nkSym: 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) e = newSymS(skEnumField, n.sons[i].sons[0], c)
var v = semConstExpr(c, n.sons[i].sons[1]) var v = semConstExpr(c, n.sons[i].sons[1])
var strVal: PNode = nil var strVal: PNode = nil
case skipTypes(v.typ, abstractInst).kind case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
of tyTuple: of tyTuple:
if sonsLen(v) == 2: if sonsLen(v) == 2:
strVal = v.sons[1] # second tuple part is the string value 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 let bound = result.typ.sons[0].sym
if bound != nil: if bound != nil:
return bound return bound
else: return result
return result.typ.sym if result.typ.sym == nil:
else: LocalError(n.info, errTypeExpected)
return result.typ.sym return errorSym(c, n)
return result.typ.sym
if result.kind != skType: if result.kind != skType:
# this implements the wanted ``var v: V, x: V`` feature ... # this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter var ov: TOverloadIter
@ -323,8 +324,8 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var biggestInt): PNode
checkMinSonsLen(t, 1) checkMinSonsLen(t, 1)
let ac = semConstExpr(c, a) let ac = semConstExpr(c, a)
let bc = semConstExpr(c, b) let bc = semConstExpr(c, b)
let at = fitNode(c, t.sons[0].typ, ac) let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
let bt = fitNode(c, t.sons[0].typ, bc) let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
result = newNodeI(nkRange, a.info) result = newNodeI(nkRange, a.info)
result.add(at) result.add(at)
@ -388,7 +389,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
return return
incl(a.sons[0].sym.flags, sfDiscriminant) incl(a.sons[0].sym.flags, sfDiscriminant)
var covered: biggestInt = 0 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): if not isOrdinalType(typ):
LocalError(n.info, errSelectorMustBeOrdinal) LocalError(n.info, errSelectorMustBeOrdinal)
elif firstOrd(typ) < 0: elif firstOrd(typ) < 0:
@ -873,6 +874,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.typ == nil: if s.typ == nil:
if s.kind != skError: LocalError(n.info, errTypeExpected) if s.kind != skError: LocalError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) 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: elif prev == nil:
result = s.typ result = s.typ
else: 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 var line = stdin.readLine.string
if line == "quit": quit() if line == "quit": quit()
execute line execute line
echo ""
FlushFile(stdout)
of "tcp", "": of "tcp", "":
var server = Socket() var server = Socket()
let p = getConfigVar("server.port") let p = getConfigVar("server.port")
@ -83,11 +86,10 @@ proc serve*(action: proc (){.nimcall.}) =
new(stdoutSocket) new(stdoutSocket)
while true: while true:
accept(server, stdoutSocket) accept(server, stdoutSocket)
discard stdoutSocket.recvLine(inp) stdoutSocket.readLine(inp)
execute inp.string execute inp.string
stdoutSocket.send("\c\L") stdoutSocket.send("\c\L")
stdoutSocket.close() stdoutSocket.close()
else: else:
echo "Invalid server.type:", typ echo "Invalid server.type:", typ
quit 1 quit 1

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

@ -97,6 +97,45 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.baseTypeMatch = b.baseTypeMatch a.baseTypeMatch = b.baseTypeMatch
copyIdTable(a.bindings, b.bindings) 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 = proc cmpCandidates*(a, b: TCandidate): int =
result = a.exactMatches - b.exactMatches result = a.exactMatches - b.exactMatches
if result != 0: return if result != 0: return
@ -110,9 +149,12 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return if result != 0: return
if (a.calleeScope != -1) and (b.calleeScope != -1): if (a.calleeScope != -1) and (b.calleeScope != -1):
result = a.calleeScope - b.calleeScope result = a.calleeScope - b.calleeScope
if result != 0: return if result != 0: return
# the other way round because of other semantics: # the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty 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) = proc writeMatches*(c: TCandidate) =
Writeln(stdout, "exact matches: " & $c.exactMatches) Writeln(stdout, "exact matches: " & $c.exactMatches)
@ -130,11 +172,18 @@ proc NotFoundError*(c: PContext, n: PNode) =
GlobalError(n.info, errTypeMismatch, "") GlobalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch) var result = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
#debug(n.sons[i].typ) var nt = n.sons[i].typ
if n.sons[i].kind == nkExprEqExpr: if n.sons[i].kind == nkExprEqExpr:
add(result, renderTree(n.sons[i].sons[0])) add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ") 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 if nt.kind == tyError: return
add(result, typeToString(nt)) add(result, typeToString(nt))
if i != sonsLen(n) - 1: add(result, ", ") if i != sonsLen(n) - 1: add(result, ", ")
@ -146,7 +195,6 @@ proc NotFoundError*(c: PContext, n: PNode) =
if sym.kind in RoutineKinds: if sym.kind in RoutineKinds:
add(candidates, getProcHeader(sym)) add(candidates, getProcHeader(sym))
add(candidates, "\n") add(candidates, "\n")
#debug(sym.typ)
sym = nextOverloadIter(o, c, n.sons[0]) sym = nextOverloadIter(o, c, n.sons[0])
if candidates != "": if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & 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 result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone 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 = proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f? # is a subtype of f?
result = isNone result = isNone
@ -338,6 +402,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = typeRel(c, base(f), base(a)) result = typeRel(c, base(f), base(a))
# bugfix: accept integer conversions here # bugfix: accept integer conversions here
#if result < isGeneric: result = isNone #if result < isGeneric: result = isNone
if result notin {isNone, isGeneric}:
result = typeRangeRel(f, a)
elif skipTypes(f, {tyRange}).kind == a.kind: elif skipTypes(f, {tyRange}).kind == a.kind:
result = isIntConv result = isIntConv
elif isConvertibleToRange(skipTypes(f, {tyRange}), a): 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) result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
of isSubrange: of isSubrange:
inc(m.subtypeMatches) inc(m.subtypeMatches)
result = copyTree(arg) #result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: 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 = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f) result.typ = getInstantiatedType(c, arg, m, f)
# BUG: f may not be the right key! # 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) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
# BUGFIX: use ``result.typ`` and not `f` here # BUGFIX: use ``result.typ`` and not `f` here
of isFromIntLit: of isFromIntLit:
@ -680,7 +747,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isEqual: of isEqual:
inc(m.exactMatches) inc(m.exactMatches)
result = copyTree(arg) 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) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isNone: of isNone:
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``: # 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) if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son 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, proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var TIntSet) = m: var TCandidate, marker: var TIntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} = template checkConstraint(n: expr) {.immediate, dirty.} =
@ -780,6 +869,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if n.sons[a].kind == nkExprEqExpr: if n.sons[a].kind == nkExprEqExpr:
# named param # named param
# check if m.callee has such a param: # check if m.callee has such a param:
prepareNamedParam(n.sons[a])
if n.sons[a].sons[0].kind != nkIdent: if n.sons[a].sons[0].kind != nkIdent:
LocalError(n.sons[a].info, errNamedParamHasToBeIdent) LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
m.state = csNoMatch m.state = csNoMatch
@ -795,6 +885,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false 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, var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1]) n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil: if arg == nil:
@ -815,13 +907,16 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
# too many arguments? # too many arguments?
if tfVarArgs in m.callee.flags: if tfVarArgs in m.callee.flags:
# is ok... but don't increment any counters... # is ok... but don't increment any counters...
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString: # 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), addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
copyTree(n.sons[a]), m, c)) copyTree(n.sons[a]), m, c))
else: else:
addSon(m.call, copyTree(n.sons[a])) addSon(m.call, copyTree(n.sons[a]))
elif formal != nil: elif formal != nil:
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil): if (arg != nil) and m.baseTypeMatch and (container != nil):
@ -843,6 +938,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if arg == nil: if arg == nil:
@ -861,6 +957,12 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
inc(a) inc(a)
inc(f) 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) = proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support: # for 'suggest' support:
var marker = initIntSet() 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

7
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: of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
# we don't include uint and uint64 here as these are no ordinal types ;-) # we don't include uint and uint64 here as these are no ordinal types ;-)
if not isOrdinalType(source): if not isOrdinalType(source):
# XXX int64 -> float conversion? # float -> int conversions. ugh.
result = transformSons(c, n) result = transformSons(c, n)
elif firstOrd(dest) <= firstOrd(source) and elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
lastOrd(source) <= lastOrd(dest): lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
# BUGFIX: simply leave n as it is; we need a nkConv node, # BUGFIX: simply leave n as it is; we need a nkConv node,
# but no range check: # but no range check:
result = transformSons(c, n) result = transformSons(c, n)
@ -341,6 +341,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(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: if skipTypes(n.typ, abstractVar).kind == tyRange:
result = newTransNode(nkChckRangeF, n, 3) result = newTransNode(nkChckRangeF, n, 3)
dest = skipTypes(n.typ, abstractVar) 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 result = true
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv: of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1]) result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar, nkClosure: of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len: for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false if not isDeepConstExpr(n.sons[i]): return false
result = true result = true

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

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

@ -49,16 +49,18 @@ proc isOrdinalType*(t: PType): bool
proc enumHasHoles*(t: PType): bool proc enumHasHoles*(t: PType): bool
const const
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable, tyTypeDesc}
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable, tyTypeDesc}
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable, tyTypeDesc}
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable, tyTypeDesc}
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal} 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} typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc}
@ -327,7 +329,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
result = false result = false
if typ == nil: return if typ == nil: return
if tfAcyclic in typ.flags: return if tfAcyclic in typ.flags: return
var t = skipTypes(typ, abstractInst) var t = skipTypes(typ, abstractInst-{tyTypeDesc})
if tfAcyclic in t.flags: return if tfAcyclic in t.flags: return
case t.kind case t.kind
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray, 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: #if t.kind == tyObject and tfFinal notin t.flags:
# # damn inheritance may introduce cycles: # # damn inheritance may introduce cycles:
# result = true # result = true
of tyProc: result = typ.callConv == ccClosure
else: nil else: nil
proc canFormAcycle(typ: PType): bool = proc canFormAcycle(typ: PType): bool =
# XXX as I expect cycles introduced by closures are very rare, we pretend
# they can't happen here.
var marker = InitIntSet() var marker = InitIntSet()
result = canFormAcycleAux(marker, typ, typ.id) result = canFormAcycleAux(marker, typ, typ.id)
@ -393,26 +394,31 @@ proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange) assert(n.kind == nkRange)
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1]) 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 = proc constraintsToStr(t: PType): string =
let sep = if tfAny in t.flags: " or " else: " and " let sep = if tfAny in t.flags: " or " else: " and "
result = "" result = ""
for i in countup(0, t.sons.len - 1): for i in countup(0, t.len - 1):
if i > 0: result.add(sep) 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 = 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 var t = typ
result = "" result = ""
if t == nil: return if t == nil: return
@ -433,12 +439,15 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
add(result, typeToString(t.sons[i])) add(result, typeToString(t.sons[i]))
add(result, ']') add(result, ']')
of tyTypeDesc: of tyTypeDesc:
if t.sons == nil or t.sons.len == 0: result = "typedesc" if t.len == 0: result = "typedesc"
else: result = "typedesc[" & constraintsToStr(t) & "]" else: result = "typedesc[" & constraintsToStr(t) & "]"
of tyTypeClass: 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: of tyExpr:
if t.sons.len == 0: result = "expr" if t.len == 0: result = "expr"
else: result = "expr[" & constraintsToStr(t) & "]" else: result = "expr[" & constraintsToStr(t) & "]"
of tyArray: of tyArray:
if t.sons[0].kind == tyRange: if t.sons[0].kind == tyRange:
@ -477,7 +486,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyPtr, tyRef, tyVar, tyMutable, tyConst: of tyPtr, tyRef, tyVar, tyMutable, tyConst:
result = typeToStr[t.kind] & typeToString(t.sons[0]) result = typeToStr[t.kind] & typeToString(t.sons[0])
of tyRange: of tyRange:
result = "range " & rangeToStr(t.n) result = "range " & rangeToStr(t.n) & "(" & typeToString(t.sons[0]) & ")"
of tyProc: of tyProc:
result = if tfIterator in t.flags: "iterator (" else: "proc (" result = if tfIterator in t.flags: "iterator (" else: "proc ("
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
@ -534,7 +543,7 @@ proc firstOrd(t: PType): biggestInt =
else: else:
assert(t.n.sons[0].kind == nkSym) assert(t.n.sons[0].kind == nkSym)
result = t.n.sons[0].sym.position result = t.n.sons[0].sym.position
of tyGenericInst, tyDistinct, tyConst, tyMutable: of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
result = firstOrd(lastSon(t)) result = firstOrd(lastSon(t))
else: else:
InternalError("invalid kind for first(" & $t.kind & ')') InternalError("invalid kind for first(" & $t.kind & ')')
@ -567,7 +576,7 @@ proc lastOrd(t: PType): biggestInt =
of tyEnum: of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position result = t.n.sons[sonsLen(t.n) - 1].sym.position
of tyGenericInst, tyDistinct, tyConst, tyMutable: of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
result = lastOrd(lastSon(t)) result = lastOrd(lastSon(t))
of tyProxy: result = 0 of tyProxy: result = 0
else: else:
@ -833,7 +842,8 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
of tyGenericInst: of tyGenericInst:
result = sameTypeAux(lastSon(a), lastSon(b), c) result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc: of tyTypeDesc:
if TypeDescExactMatch in c.flags: if c.cmp == dcEqIgnoreDistinct: result = false
elif TypeDescExactMatch in c.flags:
CycleCheck() CycleCheck()
result = sameChildrenAux(x, y, c) and sameFlags(a, b) result = sameChildrenAux(x, y, c) and sameFlags(a, b)
else: else:
@ -938,7 +948,8 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
of tyTypeClass: of tyTypeClass:
match = matchTypeClass(bindings, req, t) match = matchTypeClass(bindings, req, t)
else: nil 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) match = sameType(t, req)
if tfAny in typeClass.flags: if tfAny in typeClass.flags:
@ -962,11 +973,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = true result = true
if typ == nil: return if typ == nil: return
if ContainsOrIncl(marker, typ.id): return if ContainsOrIncl(marker, typ.id): return
var t = skipTypes(typ, abstractInst) var t = skipTypes(typ, abstractInst-{tyTypeDesc})
case t.kind case t.kind
of tyVar: of tyVar:
if kind == skConst: return false if kind == skConst: return false
var t2 = skipTypes(t.sons[0], abstractInst) var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
case t2.kind case t2.kind
of tyVar: of tyVar:
result = false # ``var var`` is always an invalid type: result = false # ``var var`` is always an invalid type:
@ -982,6 +993,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = typeAllowedAux(marker, t.sons[0], skResult) result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc: of tyExpr, tyStmt, tyTypeDesc:
result = true result = true
# XXX er ... no? these should not be allowed!
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation,
tyTypeClass: tyTypeClass:
result = false result = false
@ -994,7 +1006,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyGenericInst, tyDistinct: of tyGenericInst, tyDistinct:
result = typeAllowedAux(marker, lastSon(t), kind) result = typeAllowedAux(marker, lastSon(t), kind)
of tyRange: of tyRange:
result = skipTypes(t.sons[0], abstractInst).kind in result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
{tyChar, tyEnum, tyInt..tyFloat128} {tyChar, tyEnum, tyInt..tyFloat128}
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar) 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) result = align(result, a)
of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
result = computeSizeAux(lastSon(typ), a) result = computeSizeAux(lastSon(typ), a)
of tyTypeDesc:
result = (if typ.len == 1: computeSizeAux(typ.sons[0], a) else: -1)
of tyProxy: result = 1 of tyProxy: result = 1
else: else:
#internalError("computeSizeAux()") #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