resolved conflict

This commit is contained in:
Andreas Rumpf
2014-04-10 01:47:20 +02:00
871 changed files with 33223 additions and 14101 deletions

1
bin/empty.txt Normal file
View File

@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.

1
build/empty.txt Normal file
View File

@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.

View File

@@ -42,7 +42,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
result = arNo
if a == nil or b == nil: return
if ContainsOrIncl(marker, a.id): return
if containsOrIncl(marker, a.id): return
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind
of tyObject:
@@ -54,11 +54,11 @@ proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
for i in countup(0, sonsLen(a) - 1):
result = isPartOfAux(a.sons[i], b, marker)
if result == arYes: return
else: nil
else: discard
proc isPartOf(a, b: PType): TAnalysisResult =
## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
var marker = InitIntSet()
var marker = initIntSet()
# watch out: parameters reversed because I'm too lazy to change the code...
result = isPartOfAux(b, a, marker)
@@ -115,7 +115,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
if SameValue(x, y): result = arYes
if sameValue(x, y): result = arYes
else: result = arNo
# else: maybe and no are accurate
else:
@@ -140,7 +140,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: nil
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -177,6 +177,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else: nil
else: nil
else: discard
else: discard

View File

@@ -62,7 +62,7 @@ type
nkTripleStrLit, # a triple string literal """
nkNilLit, # the nil literal
# end of atoms
nkMetaNode, # difficult to explain; represents itself
nkMetaNode_Obsolete, # difficult to explain; represents itself
# (used for macros)
nkDotCall, # used to temporarily flag a nkCall node;
# this is used
@@ -188,10 +188,15 @@ type
nkStmtListType, # a statement list ending in a type; for macros
nkBlockType, # a statement block ending in a type; for macros
# types as syntactic trees:
nkWith, # distinct with `foo`
nkWithout, # distinct without `foo`
nkTypeOfExpr, # type(1+2)
nkObjectTy, # object body
nkTupleTy, # tuple body
nkTypeClassTy, # user-defined type class
nkStaticTy, # ``static[T]``
nkRecList, # list of object parts
nkRecCase, # case section of object
nkRecWhen, # when section of object
@@ -335,20 +340,70 @@ type
tyConst, tyMutable, tyVarargs,
tyIter, # unused
tyProxy # used as errornous type (for idetools)
tyTypeClass
tyAnd
tyOr
tyNot
tyAnything
tyParametricTypeClass # structured similarly to tyGenericInst
# lastSon is the body of the type class
tyBuiltInTypeClass #\
# Type such as the catch-all object, tuple, seq, etc
tyUserTypeClass #\
# the body of a user-defined type class
tyUserTypeClassInst #\
# Instance of a parametric user-defined type class.
# Structured similarly to tyGenericInst.
# tyGenericInst represents concrete types, while
# this is still a "generic param" that will bind types
# and resolves them during sigmatch and instantiation.
tyCompositeTypeClass #\
# Type such as seq[Number]
# The notes for tyUserTypeClassInst apply here as well
# sons[0]: the original expression used by the user.
# sons[1]: fully expanded and instantiated meta type
# (potentially following aliases)
tyAnd, tyOr, tyNot #\
# boolean type classes such as `string|int`,`not seq`,
# `Sortable and Enumable`, etc
tyAnything #\
# a type class matching any type
tyStatic #\
# a value known at compile type (the underlying type is .base)
tyFromExpr #\
# This is a type representing an expression that depends
# on generic parameters (the exprsesion is stored in t.n)
# It will be converted to a real type only during generic
# instantiation and prior to this it has the potential to
# be any type.
tyFieldAccessor #\
# Expressions such as Type.field (valid in contexts such
# as the `is` operator and magics like `high` and `low`).
# Could be lifted to a single argument proc returning the
# field value.
# sons[0]: type of containing object or tuple
# sons[1]: field type
# .n: nkDotExpr storing the field name
static:
# remind us when TTypeKind stops to fit in a single 64-bit word
assert TTypeKind.high.ord <= 63
const
tyPureObject* = tyTuple
GcTypeKinds* = {tyRef, tySequence, tyString}
tyError* = tyProxy # as an errornous node should match everything
tyTypeClasses* = {tyTypeClass, tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
tyUnknownTypes* = {tyError, tyFromExpr}
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst,
tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
type
TTypeKinds* = set[TTypeKind]
@@ -362,11 +417,14 @@ type
# efficiency
nfTransf, # node has been transformed
nfSem # node has been checked for semantics
nfDelegate # the call can use a delegator
nfDotField # the call can use a dot operator
nfDotSetter # the call can use a setter dot operarator
nfExplicitCall # x.y() was used instead of x.y
nfExprCall # this is an attempt to call a regular expression
nfIsRef # this node is a 'ref' node; used for the VM
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
tfVarargs, # procedure has C styled varargs
tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final?
@@ -378,13 +436,13 @@ type
tfFromGeneric, # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural
# type equality has to be used
tfUnresolved, # marks unresolved typedesc params: e.g.
tfUnresolved, # marks unresolved typedesc/static params: e.g.
# proc foo(T: typedesc, list: seq[T]): var T
# proc foo(L: static[int]): array[L, int]
# can be attached to ranges to indicate that the range
# depends on unresolved static params.
tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference)
tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met
tfNot, # type class with a negative check
tfCapturesEnv, # whether proc really captures some environment
tfByCopy, # pass object/tuple by copy (C backend)
tfByRef, # pass object/tuple by reference (C backend)
@@ -395,8 +453,19 @@ type
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires inititalization
tfHasShared, # type constains a "shared" constraint modifier somewhere
tfHasMeta, # type has "typedesc" or "expr" somewhere; or uses '|'
tfHasMeta, # type contains "wildcard" sub-types such as generic params
# or other type classes
tfHasGCedMem, # type contains GC'ed memory
tfPacked
tfHasStatic
tfGenericTypeParam
tfImplicitTypeParam
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
# T and I here can bind to both typedesc and static types
# before this is determined, we'll consider them to be a
# wildcard type.
tfGuarded # guarded pointer
tfBorrowDot # distinct type borrows '.'
TTypeFlags* = set[TTypeFlag]
@@ -418,7 +487,8 @@ type
skResult, # special 'result' variable
skProc, # a proc
skMethod, # a method
skIterator, # an iterator
skIterator, # an inline iterator
skClosureIterator, # a resumable closure iterator
skConverter, # a type converter
skMacro, # a macro
skTemplate, # a template; currently also misused for user-defined
@@ -430,12 +500,15 @@ type
skStub, # symbol is a stub and not yet loaded from the ROD
# file (it is loaded on demand, which may
# mean: never)
skPackage # symbol is a package (used for canonicalization)
TSymKinds* = set[TSymKind]
const
routineKinds* = {skProc, skMethod, skIterator, skConverter,
skMacro, skTemplate}
routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skMacro, skTemplate}
tfIncompleteStruct* = tfVarargs
tfUncheckedArray* = tfVarargs
tfUnion* = tfNoSideEffect
skError* = skUnknown
# type flags that are essential for type equality:
@@ -545,11 +618,11 @@ type
typ*: PType
info*: TLineInfo
flags*: TNodeFlags
case Kind*: TNodeKind
case kind*: TNodeKind
of nkCharLit..nkUInt64Lit:
intVal*: biggestInt
intVal*: BiggestInt
of nkFloatLit..nkFloat128Lit:
floatVal*: biggestFloat
floatVal*: BiggestFloat
of nkStrLit..nkTripleStrLit:
strVal*: string
of nkSym:
@@ -638,7 +711,7 @@ type
TSym* {.acyclic.} = object of TIdObj
# proc and type instantiations are cached in the generic symbol
case kind*: TSymKind
of skType:
of skType, skGenericParam:
typeInstCache*: seq[PType]
typScope*: PScope
of routineKinds:
@@ -763,19 +836,24 @@ type
counter*: int
data*: TObjectSeq
TImplication* = enum
impUnknown, impNo, impYes
# BUGFIX: a module is overloadable so that a proc can have the
# same name as an imported module. This is necessary because of
# the poor naming choices in the standard library.
const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
skModule, skTemplate, skMacro}
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam}
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
tyVarargs}
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
# var x = expr
tyBool, tyChar, tyEnum, tyArray, tyObject,
@@ -789,10 +867,12 @@ const
tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
tyProc, tyString, tyError}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
skIterator, skClosureIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
nfAllConst, nfDelegate}
nfDotSetter, nfDotField,
nfAllConst,nfIsRef}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -806,6 +886,7 @@ const
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}
nkLiterals* = {nkCharLit..nkTripleStrLit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
procDefs* = nkLambdaKinds + declarativeDefs
@@ -814,14 +895,17 @@ const
nkStrKinds* = {nkStrLit..nkTripleStrLit}
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter}
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator,
skMethod, skConverter}
skIterators* = {skIterator, skClosureIterator}
lfFullExternalName* = lfParamCopy # \
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
# imported via 'importc: "fullname"' and no format string.
# creator procs:
proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym
proc newType*(kind: TTypeKind, owner: PSym): PType
proc newNode*(kind: TNodeKind): PNode
@@ -894,6 +978,11 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it!
proc isMetaType*(t: PType): bool =
return t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil) or
tfHasMeta in t.flags
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
t.sym = s
s.typ = t
@@ -910,7 +999,7 @@ template fileIdx*(c: PSym): int32 =
template filename*(c: PSym): string =
# XXX: this should be used only on module symbols
c.position.int32.toFileName
c.position.int32.toFilename
proc appendToModule*(m: PSym, n: PNode) =
## The compiler will use this internally to add nodes that will be
@@ -929,7 +1018,7 @@ const # for all kind of hash tables:
proc copyStrTable(dest: var TStrTable, src: TStrTable) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyIdTable(dest: var TIdTable, src: TIdTable) =
@@ -941,20 +1030,20 @@ proc copyIdTable(dest: var TIdTable, src: TIdTable) =
proc copyTable(dest: var TTable, src: TTable) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc discardSons(father: PNode) =
father.sons = nil
when defined(useNodeIds):
const nodeIdToDebug = 612777 # 612794
const nodeIdToDebug* = 482228 # 612794
#612840 # 612905 # 614635 # 614637 # 614641
# 423408
#429107 # 430443 # 441048 # 441090 # 441153
@@ -990,6 +1079,10 @@ proc newStrNode(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info
return n
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent)
result.ident = ident
@@ -1051,10 +1144,6 @@ proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result.info = info
result.typ = typ
proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
result = newNodeIT(nkMetaNode, info, typ)
result.add(tree)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
@@ -1067,7 +1156,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
pragmas, exceptions, body]
proc NewType(kind: TTypeKind, owner: PSym): PType =
proc newType(kind: TTypeKind, owner: PSym): PType =
new(result)
result.kind = kind
result.owner = owner
@@ -1075,7 +1164,7 @@ proc NewType(kind: TTypeKind, owner: PSym): PType =
result.align = 2 # default alignment
result.id = getID()
when debugIds:
RegisterId(result)
registerId(result)
#if result.id < 2000 then
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
@@ -1107,12 +1196,12 @@ proc assignType(dest, src: PType) =
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
proc copyType(t: PType, owner: PSym, keepId: bool): PType =
result = newType(t.Kind, owner)
result = newType(t.kind, owner)
assignType(result, t)
if keepId:
result.id = t.id
else:
when debugIds: RegisterId(result)
when debugIds: registerId(result)
result.sym = t.sym # backend-info should not be copied
proc copySym(s: PSym, keepId: bool = false): PSym =
@@ -1123,7 +1212,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
result.id = s.id
else:
result.id = getID()
when debugIds: RegisterId(result)
when debugIds: registerId(result)
result.flags = s.flags
result.magic = s.magic
if s.kind == skModule:
@@ -1147,12 +1236,12 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
# XXX once usedGenerics is used, ensure module aliases keep working!
assert s.usedGenerics == nil
proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too
new(result)
result.Name = Name
result.Kind = symKind
result.name = name
result.kind = symKind
result.flags = {}
result.info = info
result.options = gOptions
@@ -1160,36 +1249,36 @@ proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
result.offset = - 1
result.id = getID()
when debugIds:
RegisterId(result)
registerId(result)
#if result.id < 2000:
# MessageOut(name.s & " has id: " & toString(result.id))
proc initStrTable(x: var TStrTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initTable(x: var TTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initIdTable(x: var TIdTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initObjectSet(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initIdNodeTable(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initNodeTable(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc sonsLen(n: PType): int =
if isNil(n.sons): result = 0
@@ -1203,7 +1292,7 @@ proc newSons(father: PType, length: int) =
if isNil(father.sons):
newSeq(father.sons, length)
else:
setlen(father.sons, length)
setLen(father.sons, length)
proc sonsLen(n: PNode): int =
if isNil(n.sons): result = 0
@@ -1213,7 +1302,11 @@ proc newSons(father: PNode, length: int) =
if isNil(father.sons):
newSeq(father.sons, length)
else:
setlen(father.sons, length)
setLen(father.sons, length)
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
result = t
while result.kind in kinds: result = lastSon(result)
proc propagateToOwner*(owner, elem: PType) =
const HaveTheirOwnEmpty = {tySequence, tySet}
@@ -1226,15 +1319,16 @@ proc propagateToOwner*(owner, elem: PType) =
owner.flags.incl tfNeedsInit
if tfNeedsInit in elem.flags:
if owner.kind in HaveTheirOwnEmpty: nil
if owner.kind in HaveTheirOwnEmpty: discard
else: owner.flags.incl tfNeedsInit
if tfShared in elem.flags:
owner.flags.incl tfHasShared
if elem.kind in {tyExpr, tyTypeDesc}:
if elem.isMetaType:
owner.flags.incl tfHasMeta
elif elem.kind in {tyString, tyRef, tySequence} or
if elem.kind in {tyString, tyRef, tySequence} or
elem.kind == tyProc and elem.callConv == ccClosure:
owner.flags.incl tfHasGCedMem
@@ -1256,7 +1350,7 @@ proc delSon(father: PNode, idx: int) =
if isNil(father.sons): return
var length = sonsLen(father)
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
setlen(father.sons, length - 1)
setLen(father.sons, length - 1)
proc copyNode(src: PNode): PNode =
# does not copy its sons!
@@ -1269,13 +1363,13 @@ proc copyNode(src: PNode): PNode =
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.Kind
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: nil
else: discard
proc shallowCopy*(src: PNode): PNode =
# does not copy its sons, but provides space for them:
@@ -1287,7 +1381,7 @@ proc shallowCopy*(src: PNode): PNode =
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.Kind
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
@@ -1306,7 +1400,7 @@ proc copyTree(src: PNode): PNode =
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.Kind
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
@@ -1364,14 +1458,14 @@ proc sonsNotNil(n: PNode): bool =
return false
result = true
proc getInt*(a: PNode): biggestInt =
proc getInt*(a: PNode): BiggestInt =
case a.kind
of nkIntLit..nkUInt64Lit: result = a.intVal
else:
internalError(a.info, "getInt")
result = 0
proc getFloat*(a: PNode): biggestFloat =
proc getFloat*(a: PNode): BiggestFloat =
case a.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal
else:
@@ -1398,19 +1492,22 @@ proc isGenericRoutine*(s: PSym): bool =
of skProcKinds:
result = sfFromGeneric in s.flags or
(s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
else: nil
else: discard
proc skipGenericOwner*(s: PSym): PSym =
InternalAssert s.kind in skProcKinds
internalAssert s.kind in skProcKinds
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straigh to the owner
## of the generic itself (the module or the enclosing proc).
result = if sfFromGeneric in s.flags: s.owner.owner
else: s.owner
proc originatingModule*(s: PSym): PSym =
result = s.owner
while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} =
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
skConverter}
result = s.kind in skProcKinds
proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
@@ -1418,6 +1515,9 @@ proc hasPattern*(s: PSym): bool {.inline.} =
iterator items*(n: PNode): PNode =
for i in 0.. <n.len: yield n.sons[i]
iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
for i in 0.. <n.len: yield (i, n.sons[i])
proc isAtom*(n: PNode): bool {.inline.} =
result = n.kind >= nkNone and n.kind <= nkNilLit

View File

@@ -24,35 +24,35 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
proc lineInfoToStr*(info: TLineInfo): PRope
# ----------------------- node sets: ---------------------------------------
proc ObjectSetContains*(t: TObjectSet, obj: PObject): bool
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
# returns true whether n is in t
proc ObjectSetIncl*(t: var TObjectSet, obj: PObject)
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
# include an element n in the table t
proc ObjectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
# more are not needed ...
# ----------------------- (key, val)-Hashtables ----------------------------
proc TablePut*(t: var TTable, key, val: PObject)
proc TableGet*(t: TTable, key: PObject): PObject
proc tablePut*(t: var TTable, key, val: PObject)
proc tableGet*(t: TTable, key: PObject): PObject
type
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
proc TableSearch*(t: TTable, key, closure: PObject,
proc tableSearch*(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject
# return val as soon as comparator returns true; if this never happens,
# nil is returned
# ----------------------- str table -----------------------------------------
proc StrTableContains*(t: TStrTable, n: PSym): bool
proc StrTableAdd*(t: var TStrTable, n: PSym)
proc StrTableGet*(t: TStrTable, name: PIdent): PSym
proc strTableContains*(t: TStrTable, n: PSym): bool
proc strTableAdd*(t: var TStrTable, n: PSym)
proc strTableGet*(t: TStrTable, name: PIdent): PSym
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
# var
# i: TTabIter
@@ -69,8 +69,8 @@ type
name*: PIdent
proc InitIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
proc NextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
# these are for debugging only: They are not really deprecated, but I want
# the warning so that release versions do not contain debugging statements:
@@ -79,15 +79,14 @@ proc debug*(n: PType) {.deprecated.}
proc debug*(n: PNode) {.deprecated.}
# --------------------------- ident tables ----------------------------------
proc IdTableGet*(t: TIdTable, key: PIdObj): PObject
proc IdTableGet*(t: TIdTable, key: int): PObject
proc IdTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
proc IdTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
proc idTableGet*(t: TIdTable, key: int): PObject
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id)
proc IdNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc IdNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
proc writeIdNodeTable*(t: TIdNodeTable)
proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
# ---------------------------------------------------------------------------
@@ -111,9 +110,9 @@ type
data*: TIIPairSeq
proc initIITable*(x: var TIITable)
proc IITableGet*(t: TIITable, key: int): int
proc IITablePut*(t: var TIITable, key, val: int)
proc initIiTable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
# implementation
@@ -129,7 +128,7 @@ 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
case a.kind
of nkCharLit..nkInt64Lit:
@@ -141,7 +140,7 @@ proc SameValue*(a, b: PNode): bool =
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "SameValue")
nil
discard
proc leValue*(a, b: PNode): bool =
# a <= b?
@@ -156,7 +155,13 @@ proc leValue*(a, b: PNode): bool =
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "leValue")
nil
discard
proc weakLeValue*(a, b: PNode): TImplication =
if a.kind notin nkLiterals or b.kind notin nkLiterals:
result = impUnknown
else:
result = if leValue(a, b): impYes else: impNo
proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = nil
@@ -166,7 +171,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = lookupInRecord(n.sons[i], field)
if result != nil: return
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "lookupInRecord")
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
result = lookupInRecord(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
@@ -182,14 +187,14 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
proc getModule(s: PSym): PSym =
result = s
assert((result.kind == skModule) or (result.owner != result))
while (result != nil) and (result.kind != skModule): result = result.owner
while result != nil and result.kind != skModule: result = result.owner
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in countup(start, sonsLen(list) - 1):
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
if result.name.id == ident.id: return
else: InternalError(list.info, "getSymFromList")
else: internalError(list.info, "getSymFromList")
result = nil
proc hashNode(p: PObject): THash =
@@ -203,7 +208,7 @@ proc spaces(x: int): PRope =
# returns x spaces
result = toRope(repeatChar(x))
proc toYamlChar(c: Char): string =
proc toYamlChar(c: char): string =
case c
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c
@@ -216,7 +221,7 @@ proc makeYamlString*(s: string): PRope =
const MaxLineLength = 64
result = nil
var res = "\""
for i in countup(0, len(s) - 1):
for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, "\n")
@@ -262,7 +267,7 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
app(result, "]")
assert(mycount == n.counter)
proc ropeConstr(indent: int, c: openarray[PRope]): PRope =
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
# array of (name, value) pairs
var istr = spaces(indent + 2)
result = toRope("{")
@@ -277,7 +282,7 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif ContainsOrIncl(marker, n.id):
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else:
@@ -298,7 +303,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif ContainsOrIncl(marker, n.id):
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else:
@@ -315,7 +320,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
makeYamlString($n.kind),
toRope("sym"), symToYamlAux(n.sym, marker,
indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker,
indent + 2, maxRecDepth - 1), toRope("flags"), FlagsToStr(n.flags),
indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags),
toRope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]),
toRope("size"), toRope(n.size),
@@ -336,9 +341,12 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
[istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr])
else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
appf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
@@ -360,15 +368,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
appf(result, "$N$1}", [spaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = treeToYamlAux(n, marker, indent, maxRecDepth)
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = typeToYamlAux(n, marker, indent, maxRecDepth)
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = symToYamlAux(n, marker, indent, maxRecDepth)
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope
@@ -406,9 +414,12 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
[istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr])
else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
appf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
@@ -433,6 +444,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
proc debug(n: PSym) =
if n == nil:
writeln(stdout, "null")
elif n.kind == skUnknown:
writeln(stdout, "skUnknown")
else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
@@ -454,18 +467,18 @@ proc nextTry(h, maxHash: THash): THash =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
# returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == obj):
while t.data[h] != nil:
if t.data[h] == obj:
return true
h = nextTry(h, high(t.data))
result = false
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
var h: THash = HashNode(obj) and high(data)
while data[h] != nil:
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
var h: THash = hashNode(obj) and high(data)
while data[h] != nil:
assert(data[h] != obj)
h = nextTry(h, high(data))
assert(data[h] == nil)
@@ -473,8 +486,8 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
proc objectSetEnlarge(t: var TObjectSet) =
var n: TObjectSeq
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n)
@@ -485,7 +498,7 @@ proc objectSetIncl(t: var TObjectSet, obj: PObject) =
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
# returns true if obj is already in the string table:
var h: THash = HashNode(obj) and high(t.data)
var h: THash = hashNode(obj) and high(t.data)
while true:
var it = t.data[h]
if it == nil: break
@@ -501,7 +514,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
inc(t.counter)
result = false
proc TableRawGet(t: TTable, key: PObject): int =
proc tableRawGet(t: TTable, key: PObject): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
@@ -509,7 +522,7 @@ proc TableRawGet(t: TTable, key: PObject): int =
h = nextTry(h, high(t.data))
result = -1
proc TableSearch(t: TTable, key, closure: PObject,
proc tableSearch(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
@@ -520,13 +533,13 @@ proc TableSearch(t: TTable, key, closure: PObject,
h = nextTry(h, high(t.data))
result = nil
proc TableGet(t: TTable, key: PObject): PObject =
var index = TableRawGet(t, key)
proc tableGet(t: TTable, key: PObject): PObject =
var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
var h: THash = HashNode(key) and high(data)
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
var h: THash = hashNode(key) and high(data)
while data[h].key != nil:
assert(data[h].key != key)
h = nextTry(h, high(data))
@@ -534,23 +547,23 @@ proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
data[h].key = key
data[h].val = val
proc TableEnlarge(t: var TTable) =
proc tableEnlarge(t: var TTable) =
var n: TPairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil: TableRawInsert(n, t.data[i].key, t.data[i].val)
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc TablePut(t: var TTable, key, val: PObject) =
var index = TableRawGet(t, key)
proc tablePut(t: var TTable, key, val: PObject) =
var index = tableRawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter): TableEnlarge(t)
TableRawInsert(t.data, key, val)
if mustRehash(len(t.data), t.counter): tableEnlarge(t)
tableRawInsert(t.data, key, val)
inc(t.counter)
proc StrTableContains(t: TStrTable, n: PSym): bool =
proc strTableContains(t: TStrTable, n: PSym): bool =
var h: THash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == n):
@@ -558,18 +571,35 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
h = nextTry(h, high(t.data))
result = false
proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
proc strTableRawInsert(data: var TSymSeq, n: PSym) =
var h: THash = n.name.h and high(data)
while data[h] != nil:
if data[h] == n:
# allowed for 'export' feature:
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
return
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
if sfImmediate notin n.flags:
# fast path:
while data[h] != nil:
if data[h] == n:
# allowed for 'export' feature:
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
return
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
else:
# slow path; we have to ensure immediate symbols are preferred for
# symbol lookups.
# consider the chain: foo (immediate), foo, bar, bar (immediate)
# then bar (immediate) gets replaced with foo (immediate) and the non
# immediate foo is picked! Thus we need to replace it with the first
# slot that has in fact the same identifier stored in it!
var favPos = -1
while data[h] != nil:
if data[h] == n: return
if favPos < 0 and data[h].name.id == n.name.id: favPos = h
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
if favPos >= 0: swap data[h], data[favPos]
proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: THash = prevSym.name.h and high(data)
while data[h] != nil:
@@ -579,22 +609,22 @@ proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
h = nextTry(h, high(data))
assert false
proc SymTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
SymTabReplaceRaw(t.data, prevSym, newSym)
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
symTabReplaceRaw(t.data, prevSym, newSym)
proc StrTableEnlarge(t: var TStrTable) =
proc strTableEnlarge(t: var TStrTable) =
var n: TSymSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i] != nil: StrTableRawInsert(n, t.data[i])
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n)
proc StrTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): StrTableEnlarge(t)
StrTableRawInsert(t.data, n)
proc strTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n)
inc(t.counter)
proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
# returns true if n is already in the string table:
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
@@ -608,15 +638,15 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
return true # found it
h = nextTry(h, high(t.data))
if mustRehash(len(t.data), t.counter):
StrTableEnlarge(t)
StrTableRawInsert(t.data, n)
strTableEnlarge(t)
strTableRawInsert(t.data, n)
else:
assert(t.data[h] == nil)
t.data[h] = n
inc(t.counter)
result = false
proc StrTableGet(t: TStrTable, name: PIdent): PSym =
proc strTableGet(t: TStrTable, name: PIdent): PSym =
var h: THash = name.h and high(t.data)
while true:
result = t.data[h]
@@ -624,19 +654,19 @@ proc StrTableGet(t: TStrTable, name: PIdent): PSym =
if result.name.id == name.id: break
h = nextTry(h, high(t.data))
proc InitIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h
ti.name = s
if tab.Counter == 0: result = nil
else: result = NextIdentIter(ti, tab)
if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab)
proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
var h, start: THash
h = ti.h and high(tab.data)
start = h
result = tab.data[h]
while result != nil:
if result.Name.id == ti.name.id: break
if result.name.id == ti.name.id: break
h = nextTry(h, high(tab.data))
if h == start:
result = nil
@@ -644,13 +674,13 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: TIntSet): PSym =
var h: THash = ti.h and high(tab.data)
var start = h
result = tab.data[h]
while result != nil:
if result.Name.id == ti.name.id and not Contains(excluding, result.id):
if result.name.id == ti.name.id and not contains(excluding, result.id):
break
h = nextTry(h, high(tab.data))
if h == start:
@@ -658,35 +688,35 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
break
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
if result != nil and Contains(excluding, result.id): result = nil
if result != nil and contains(excluding, result.id): result = nil
proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: TIntSet): PSym =
ti.h = s.h
ti.name = s
if tab.Counter == 0: result = nil
else: result = NextIdentExcluding(ti, tab, excluding)
if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding)
proc InitTabIter(ti: var TTabIter, tab: TStrTable): PSym =
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0 # we start by zero ...
if tab.counter == 0:
result = nil # FIX 1: removed endless loop
else:
result = NextIter(ti, tab)
result = nextIter(ti, tab)
proc NextIter(ti: var TTabIter, tab: TStrTable): PSym =
proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
result = nil
while (ti.h <= high(tab.data)):
result = tab.data[ti.h]
Inc(ti.h) # ... and increment by one always
inc(ti.h) # ... and increment by one always
if result != nil: break
iterator items*(tab: TStrTable): PSym =
var it: TTabIter
var s = InitTabIter(it, tab)
var s = initTabIter(it, tab)
while s != nil:
yield s
s = NextIter(it, tab)
s = nextIter(it, tab)
proc hasEmptySlot(data: TIdPairSeq): bool =
for h in countup(0, high(data)):
@@ -694,27 +724,27 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
return true
result = false
proc IdTableRawGet(t: TIdTable, key: int): int =
proc idTableRawGet(t: TIdTable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
while t.data[h].key != nil:
if (t.data[h].key.id == key):
if t.data[h].key.id == key:
return h
h = nextTry(h, high(t.data))
result = - 1
proc IdTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = IdTableRawGet(t, key.id)
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key
else: result = false
proc IdTableGet(t: TIdTable, key: PIdObj): PObject =
var index = IdTableRawGet(t, key.id)
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
proc IdTableGet(t: TIdTable, key: int): PObject =
var index = IdTableRawGet(t, key)
proc idTableGet(t: TIdTable, key: int): PObject =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
@@ -723,7 +753,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
var h: THash
h = key.id and high(data)
while data[h].key != nil:
@@ -733,33 +763,30 @@ proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
data[h].key = key
data[h].val = val
proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
var
index: int
n: TIdPairSeq
index = IdTableRawGet(t, key.id)
index = idTableRawGet(t, key.id)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil:
IdTableRawInsert(n, t.data[i].key, t.data[i].val)
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
IdTableRawInsert(t.data, key, val)
idTableRawInsert(t.data, key, val)
inc(t.counter)
iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc writeIdNodeTable(t: TIdNodeTable) =
nil
proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
@@ -768,17 +795,17 @@ proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
h = nextTry(h, high(t.data))
result = - 1
proc IdNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int
index = IdNodeTableRawGet(t, key)
index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc IdNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
if not isNil(t.data):
result = IdNodeTableGet(t, key)
result = idNodeTableGet(t, key)
proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash
h = key.id and high(data)
while data[h].key != nil:
@@ -788,25 +815,25 @@ proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
data[h].key = key
data[h].val = val
proc IdNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = IdNodeTableRawGet(t, key)
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
var n: TIdNodePairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil:
IdNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
IdNodeTableRawInsert(t.data, key, val)
idNodeTableRawInsert(t.data, key, val)
inc(t.counter)
proc IdNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
if isNil(t.data): initIdNodeTable(t)
IdNodeTablePut(t, key, val)
idNodeTablePut(t, key, val)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data):
@@ -814,24 +841,23 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, startSize)
for i in countup(0, startSize - 1): x.data[i].key = InvalidKey
newSeq(x.data, StartSize)
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
proc IITableRawGet(t: TIITable, key: int): int =
proc iiTableRawGet(t: TIITable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
while t.data[h].key != InvalidKey:
if (t.data[h].key == key):
return h
if t.data[h].key == key: return h
h = nextTry(h, high(t.data))
result = - 1
result = -1
proc IITableGet(t: TIITable, key: int): int =
var index = IITableRawGet(t, key)
proc iiTableGet(t: TIITable, key: int): int =
var index = iiTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = InvalidKey
proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
var h: THash
h = key and high(data)
while data[h].key != InvalidKey:
@@ -841,19 +867,19 @@ proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
data[h].key = key
data[h].val = val
proc IITablePut(t: var TIITable, key, val: int) =
var index = IITableRawGet(t, key)
proc iiTablePut(t: var TIITable, key, val: int) =
var index = iiTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != InvalidKey)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
var n: TIIPairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(n)): n[i].key = InvalidKey
for i in countup(0, high(t.data)):
if t.data[i].key != InvalidKey:
IITableRawInsert(n, t.data[i].key, t.data[i].val)
iiTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
IITableRawInsert(t.data, key, val)
iiTableRawInsert(t.data, key, val)
inc(t.counter)

View File

@@ -13,7 +13,7 @@ import parseutils, strutils, strtabs, os, options, msgs, lists
proc addPath*(path: string, info: TLineInfo) =
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
lists.prependStr(options.searchPaths, path)
proc versionSplitPos(s: string): int =
result = s.len-2
@@ -45,9 +45,9 @@ proc `<.`(a, b: string): bool =
proc addPackage(packages: PStringTable, p: string) =
let x = versionSplitPos(p)
let name = p.subStr(0, x-1)
let name = p.substr(0, x-1)
if x < p.len:
let version = p.subStr(x+1)
let version = p.substr(x+1)
if packages[name] <. version:
packages[name] = version
else:
@@ -60,8 +60,8 @@ iterator chosen(packages: PStringTable): string =
proc addBabelPath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p):
if gVerbosity >= 1: Message(info, hintPath, p)
lists.PrependStr(options.lazyPaths, p)
if gVerbosity >= 1: message(info, hintPath, p)
lists.prependStr(options.lazyPaths, p)
proc addPathWithNimFiles(p: string, info: TLineInfo) =
proc hasNimFile(dir: string): bool =

View File

@@ -18,53 +18,53 @@ type
const
ElemSize* = sizeof(int8) * 8
proc BitSetInit*(b: var TBitSet, length: int)
proc BitSetUnion*(x: var TBitSet, y: TBitSet)
proc BitSetDiff*(x: var TBitSet, y: TBitSet)
proc BitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc BitSetIntersect*(x: var TBitSet, y: TBitSet)
proc BitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc BitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc BitSetIn*(x: TBitSet, e: BiggestInt): bool
proc BitSetEquals*(x, y: TBitSet): bool
proc BitSetContains*(x, y: TBitSet): bool
proc bitSetInit*(b: var TBitSet, length: int)
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
proc bitSetDiff*(x: var TBitSet, y: TBitSet)
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
proc bitSetEquals*(x, y: TBitSet): bool
proc bitSetContains*(x, y: TBitSet): bool
# implementation
proc BitSetIn(x: TBitSet, e: BiggestInt): bool =
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
toU8(0)
proc BitSetIncl(x: var TBitSet, elem: BiggestInt) =
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
assert(elem >= 0)
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
toU8(int(1 shl (elem mod ElemSize)))
proc BitSetExcl(x: var TBitSet, elem: BiggestInt) =
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
not toU8(int(1 shl (elem mod ElemSize)))
proc BitSetInit(b: var TBitSet, length: int) =
proc bitSetInit(b: var TBitSet, length: int) =
newSeq(b, length)
proc BitSetUnion(x: var TBitSet, y: TBitSet) =
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] or y[i]
proc BitSetDiff(x: var TBitSet, y: TBitSet) =
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and not y[i]
proc BitSetSymDiff(x: var TBitSet, y: TBitSet) =
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] xor y[i]
proc BitSetIntersect(x: var TBitSet, y: TBitSet) =
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and y[i]
proc BitSetEquals(x, y: TBitSet): bool =
proc bitSetEquals(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if x[i] != y[i]:
return false
result = true
proc BitSetContains(x, y: TBitSet): bool =
proc bitSetContains(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if (x[i] and not y[i]) != int8(0):
return false

View File

@@ -34,25 +34,36 @@ Options:
--skipcomments do not copy comments
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
--keepBodies keep C++'s method bodies
--spliceHeader parse and emit header before source file
-v, --version write c2nim's version
-h, --help show this help
"""
proc main(infile, outfile: string, options: PParserOptions) =
var start = getTime()
var stream = LLStreamOpen(infile, fmRead)
proc parse(infile: string, options: PParserOptions): PNode =
var stream = llStreamOpen(infile, fmRead)
if stream == nil: rawMessage(errCannotOpenFile, infile)
var p: TParser
openParser(p, infile, stream, options)
var module = parseUnit(p)
result = parseUnit(p)
closeParser(p)
renderModule(module, outfile)
proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) =
var start = getTime()
if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")):
var header_module = parse(infile.changeFileExt(".h"), options)
var source_module = parse(infile, options)
for n in source_module:
addson(header_module, n)
renderModule(header_module, outfile)
else:
renderModule(parse(infile, options), outfile)
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
formatSize(getTotalMem())])
var
infile = ""
outfile = ""
spliceHeader = false
parserOptions = newParserOptions()
for kind, key, val in getopt():
case kind
@@ -66,6 +77,7 @@ for kind, key, val in getopt():
stdout.write(Version & "\n")
quit(0)
of "o", "out": outfile = val
of "spliceheader": spliceHeader = true
else:
if not parserOptions.setOption(key, val):
stdout.writeln("[Error] unknown option: " & key)
@@ -77,4 +89,4 @@ else:
if outfile.len == 0:
outfile = changeFileExt(infile, "nim")
infile = addFileExt(infile, "h")
main(infile, outfile, parserOptions)
main(infile, outfile, parserOptions, spliceHeader)

View File

@@ -103,7 +103,7 @@ type
inDirective: bool
proc getTok*(L: var TLexer, tok: var TToken)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc `$`*(tok: TToken): string
# implementation
@@ -138,7 +138,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
msgs.GlobalError(info, msg, arg)
proc TokKindToStr*(k: TTokKind): string =
proc tokKindToStr*(k: TTokKind): string =
case k
of pxEof: result = "[EOF]"
of pxInvalid: result = "[invalid]"
@@ -211,9 +211,9 @@ proc `$`(tok: TToken): string =
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
of pxIntLit, pxInt64Lit: result = $tok.iNumber
of pxFloatLit: result = $tok.fNumber
else: result = TokKindToStr(tok.xkind)
else: result = tokKindToStr(tok.xkind)
proc PrintTok(tok: TToken) =
proc printTok(tok: TToken) =
writeln(stdout, $tok)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
@@ -223,12 +223,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
add(tok.s, '_')
Inc(pos)
inc(pos)
L.bufPos = pos
proc isFloatLiteral(s: string): bool =
@@ -239,7 +239,7 @@ proc isFloatLiteral(s: string): bool =
proc getNumber2(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0b
tok.base = base2
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -264,7 +264,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
proc getNumber8(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 1 # skip 0
tok.base = base8
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -289,7 +289,7 @@ proc getNumber8(L: var TLexer, tok: var TToken) =
proc getNumber16(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0x
tok.base = base16
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -315,19 +315,34 @@ proc getNumber16(L: var TLexer, tok: var TToken) =
else: tok.xkind = pxIntLit
L.bufpos = pos
proc getFloating(L: var TLexer, tok: var TToken) =
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] in {'e', 'E'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'0'..'9'})
proc getNumber(L: var TLexer, tok: var TToken) =
tok.base = base10
matchUnderscoreChars(L, tok, {'0'..'9'})
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
add(tok.s, '.')
if L.buf[L.bufpos] == '.':
add(tok.s, "0.")
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
getFloating(L, tok)
else:
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] == '.':
add(tok.s, '.')
inc(L.bufpos)
getFloating(L, tok)
try:
if isFloatLiteral(tok.s):
tok.fnumber = parseFloat(tok.s)
tok.xkind = pxFloatLit
else:
tok.iNumber = ParseInt(tok.s)
tok.iNumber = parseInt(tok.s)
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
tok.xkind = pxInt64Lit
else:
@@ -339,10 +354,10 @@ proc getNumber(L: var TLexer, tok: var TToken) =
# ignore type suffix:
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR: result = nimlexbase.HandleCR(L, pos)
of LF: result = nimlexbase.HandleLF(L, pos)
of CR: result = nimlexbase.handleCR(L, pos)
of LF: result = nimlexbase.handleLF(L, pos)
else: result = pos
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
@@ -382,6 +397,23 @@ proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
add(tok.s, chr(xi))
of 'x':
var xi = 0
inc(L.bufpos)
while true:
case L.buf[L.bufpos]
of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
of 'a'..'f':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
inc(L.bufpos)
of 'A'..'F':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
inc(L.bufpos)
else:
break
add(tok.s, chr(xi))
elif not allowEmpty:
lexMessage(L, errInvalidCharacterConstant)
@@ -405,7 +437,7 @@ proc getString(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of '\"':
Inc(pos)
inc(pos)
break
of CR:
pos = nimlexbase.HandleCR(L, pos)
@@ -427,7 +459,7 @@ proc getString(L: var TLexer, tok: var TToken) =
pos = L.bufpos
else:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxStrLit
@@ -438,7 +470,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
var c = buf[pos]
if c notin SymChars: break
add(tok.s, c)
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxSymbol
@@ -475,7 +507,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.s, "\n#")
# skip annoying stars as line prefix: (eg.
@@ -511,12 +543,12 @@ proc skip(L: var TLexer, tok: var TToken) =
if L.inDirective:
while buf[pos] in {' ', '\t'}: inc(pos)
if buf[pos] in {CR, LF}:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
of ' ', Tabulator:
Inc(pos) # newline is special:
inc(pos) # newline is special:
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
if L.inDirective:
tok.xkind = pxNewLine
@@ -559,13 +591,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
of 'b', 'B': getNumber2(L, tok)
of '1'..'7': getNumber8(L, tok)
else: getNumber(L, tok)
elif c in {'1'..'9'}:
elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}):
getNumber(L, tok)
else:
case c
of ';':
tok.xkind = pxSemicolon
Inc(L.bufpos)
inc(L.bufpos)
of '/':
if L.buf[L.bufpos + 1] == '/':
scanLineComment(L, tok)
@@ -580,9 +612,9 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of ',':
tok.xkind = pxComma
Inc(L.bufpos)
inc(L.bufpos)
of '(':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParLe
of '*':
inc(L.bufpos)
@@ -592,13 +624,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxStar
of ')':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParRi
of '[':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketLe
of ']':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketRi
of '.':
inc(L.bufpos)
@@ -608,10 +640,10 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxDot
of '{':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyLe
of '}':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyRi
of '+':
inc(L.bufpos)
@@ -752,4 +784,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.s = $c
tok.xkind = pxInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)

File diff suppressed because it is too large Load Diff

View File

@@ -103,7 +103,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
m.body.add(tok)
of pxDirConc:
# just ignore this token: this implements token merging correctly
nil
discard
else:
m.body.add(p.tok)
# we do not want macro expansion here:
@@ -166,7 +166,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxDirectiveParLe, pxDirective:
case p.tok.s
of "else", "endif", "elif": break
else: nil
else: discard
addSon(result, statement(p))
proc eatEndif(p: var TParser) =
@@ -226,7 +226,7 @@ proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =
proc parseIfdef(p: var TParser): PNode =
getTok(p) # skip #ifdef
ExpectIdent(p)
expectIdent(p)
case p.tok.s
of "__cplusplus":
skipUntilEndif(p)
@@ -245,7 +245,7 @@ proc parseIfdef(p: var TParser): PNode =
proc parseIfndef(p: var TParser): PNode =
result = ast.emptyNode
getTok(p) # skip #ifndef
ExpectIdent(p)
expectIdent(p)
if p.tok.s == c2nimSymbol:
skipLine(p)
case skipUntilElifElseEndif(p)
@@ -282,11 +282,11 @@ proc parseIfDir(p: var TParser): PNode =
proc parsePegLit(p: var TParser): TPeg =
var col = getColumn(p.lex) + 2
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
try:
result = parsePeg(
pattern = if p.tok.xkind == pxStrLit: p.tok.s else: escapePeg(p.tok.s),
filename = p.lex.fileIdx.ToFilename,
filename = p.lex.fileIdx.toFilename,
line = p.lex.linenumber,
col = col)
getTok(p)
@@ -295,7 +295,7 @@ proc parsePegLit(p: var TParser): TPeg =
proc parseMangleDir(p: var TParser) =
var pattern = parsePegLit(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
p.options.mangleRules.add((pattern, p.tok.s))
getTok(p)
eatNewLine(p, nil)
@@ -326,7 +326,7 @@ proc parseDir(p: var TParser): PNode =
of "dynlib", "header", "prefix", "suffix", "class":
var key = p.tok.s
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
discard setOption(p.options, key, p.tok.s)
getTok(p)
eatNewLine(p, nil)

View File

@@ -0,0 +1,33 @@
#include <stdlib.h>
#include <stdio.h>
int rand(void);
int id2(void) {
return (int *)1;
}
int id(void (*f)(void)) {
f();
((void (*)(int))f)(10);
return 10;
return (20+1);
return (int *)id;
}
int main() {
float f = .2,
g = 2.,
h = 1.0+rand(),
i = 1.0e+3;
int j, a;
for(j = 0, a = 10; j < 0; j++, a++) ;
do {
printf("howdy");
} while(--i, 0);
if(1)
printf("1"); // error from this comment
else
printf("2");
return '\x00';
}

View File

@@ -0,0 +1,3 @@
struct foo {
int x,y,z;
};

416
compiler/canonicalizer.nim Normal file
View File

@@ -0,0 +1,416 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the canonalization for the various caching mechanisms.
import strutils, db_sqlite, md5
var db: TDbConn
# We *hash* the relevant information into 128 bit hashes. This should be good
# enough to prevent any collisions.
type
TUid = distinct MD5Digest
# For name mangling we encode these hashes via a variant of base64 (called
# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
# So a signature like:
#
# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
#
# is mangled into:
# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
#
# This is a good compromise between correctness and brevity. ;-)
const
cb64 = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"_A", "_B"]
proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
result = newStringOfCap(((len + 2) div 3) * 4)
var i = 0
while i < s.len - 2:
let a = ord(s[i])
let b = ord(s[i+1])
let c = ord(s[i+2])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result.add cb64[c and 0x3F]
inc(i, 3)
if i < s.len-1:
let a = ord(s[i])
let b = ord(s[i+1])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2)]
elif i < s.len:
let a = ord(s[i])
result.add cb64[a shr 2]
result.add cb64[(a and 3) shl 4]
proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
var it = s.owner
while it != nil:
hashSym(c, it)
c &= "."
it = s.owner
c &= s.name.s
proc hashTree(c: var MD5Context, n: PNode) =
if n == nil:
c &= "\255"
return
var k = n.kind
md5Update(c, cast[cstring](addr(k)), 1)
# we really must not hash line information. 'n.typ' is debatable but
# shouldn't be necessary for now and avoids potential infinite recursions.
case n.kind
of nkEmpty, nkNilLit, nkType: discard
of nkIdent:
c &= n.ident.s
of nkSym:
hashSym(c, n.sym)
of nkCharLit..nkUInt64Lit:
var v = n.intVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkFloatLit..nkFloat64Lit:
var v = n.floatVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkStrLit..nkTripleStrLit:
c &= n.strVal
else:
for i in 0.. <n.len: hashTree(c, n.sons[i])
proc hashType(c: var MD5Context, t: PType) =
# modelled after 'typeToString'
if t == nil:
c &= "\254"
return
var k = t.kind
md5Update(c, cast[cstring](addr(k)), 1)
if t.sym != nil and sfAnon notin t.sym.flags:
# t.n for literals, but not for e.g. objects!
if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
c.hashSym(t.sym)
case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvokation:
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
c.hashType t.sons[i]
of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil
c &= t.sym.owner.name.s
of tyUserTypeClassInst:
let body = t.base
c.hashSym body.sym
for i in countup(1, sonsLen(t) - 2):
c.hashType t.sons[i]
of tyFromExpr, tyFieldAccessor:
c.hashTree(t.n)
of tyArrayConstr:
c.hashTree(t.sons[0].n)
c.hashType(t.sons[1])
of tyTuple:
if t.n != nil:
assert(sonsLen(t.n) == sonsLen(t))
for i in countup(0, sonsLen(t.n) - 1):
assert(t.n.sons[i].kind == nkSym)
c &= t.n.sons[i].sym.name.s
c &= ":"
c.hashType(t.sons[i])
c &= ","
else:
for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i]
of tyRange:
c.hashTree(t.n)
c.hashType(t.sons[0])
of tyProc:
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
for i in 0.. <t.len: c.hashType(t.sons[i])
md5Update(c, cast[cstring](addr(t.callConv)), 1)
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
else:
for i in 0.. <t.len: c.hashType(t.sons[i])
if tfShared in t.flags: c &= "shared"
if tfNotNil in t.flags: c &= "not nil"
proc canonConst(n: PNode): TUid =
var c: MD5Context
md5Init(c)
c.hashTree(n)
c.hashType(n.typ)
md5Final(c, MD5Digest(result))
proc canonSym(s: PSym): TUid =
var c: MD5Context
md5Init(c)
c.hashSym(s)
md5Final(c, MD5Digest(result))
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) =
if n == nil:
# nil nodes have to be stored too:
result.add("()")
return
result.add('(')
encodeVInt(ord(n.kind), result)
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(n.info)), result)
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
var f = n.flags * PersistentNodeFlags
if f != {}:
result.add('$')
encodeVInt(cast[int32](f), result)
if n.typ != nil:
result.add('^')
encodeVInt(n.typ.id, result)
pushType(w, n.typ)
case n.kind
of nkCharLit..nkInt64Lit:
if n.intVal != 0:
result.add('!')
encodeVBiggestInt(n.intVal, result)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
result.add('!')
encodeStr($n.floatVal, result)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
result.add('!')
encodeStr(n.strVal, result)
of nkIdent:
result.add('!')
encodeStr(n.ident.s, result)
of nkSym:
result.add('!')
encodeVInt(n.sym.id, result)
pushSym(w, n.sym)
else:
for i in countup(0, sonsLen(n) - 1):
encodeNode(w, n.info, n.sons[i], result)
add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.s != low(loc.s):
add(result, '*')
encodeVInt(ord(loc.s), result)
if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil:
add(result, '^')
encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
encodeStr(ropeToStr(loc.r), result)
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t == nil:
# nil nodes have to be stored too:
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
if t.callConv != low(t.callConv):
add(result, '?')
encodeVInt(ord(t.callConv), result)
if t.owner != nil:
add(result, '*')
encodeVInt(t.owner.id, result)
pushSym(w, t.owner)
if t.sym != nil:
add(result, '&')
encodeVInt(t.sym.id, result)
pushSym(w, t.sym)
if t.size != - 1:
add(result, '/')
encodeVBiggestInt(t.size, result)
if t.align != 2:
add(result, '=')
encodeVInt(t.align, result)
encodeLoc(w, t.loc, result)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
add(result, "^()")
else:
add(result, '^')
encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
encodeStr(ropeToStr(lib.name), result)
add(result, '|')
encodeNode(w, info, lib.path, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s == nil:
# nil nodes have to be stored too:
result.add("{}")
return
# we need no surrounding {} here because the symbol is in a line of its own
encodeVInt(ord(s.kind), result)
result.add('+')
encodeVInt(s.id, result)
result.add('&')
encodeStr(s.name.s, result)
if s.typ != nil:
result.add('^')
encodeVInt(s.typ.id, result)
pushType(w, s.typ)
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(s.info)), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
pushSym(w, s.owner)
if s.flags != {}:
result.add('$')
encodeVInt(cast[int32](s.flags), result)
if s.magic != mNone:
result.add('@')
encodeVInt(ord(s.magic), result)
if s.options != w.options:
result.add('!')
encodeVInt(cast[int32](s.options), result)
if s.position != 0:
result.add('%')
encodeVInt(s.position, result)
if s.offset != - 1:
result.add('`')
encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nimrod's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)
proc createDb() =
db.exec(sql"""
create table if not exists Module(
id integer primary key,
name varchar(256) not null,
fullpath varchar(256) not null,
interfHash varchar(256) not null,
fullHash varchar(256) not null,
created timestamp not null default (DATETIME('now')),
);""")
db.exec(sql"""
create table if not exists Symbol(
id integer primary key,
module integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references module(id)
);""")
db.exec(sql"""
create table if not exists Type(
id integer primary key,
module integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references module(id)
);""")
#db.exec(sql"""
# --create unique index if not exists TsstNameIx on TestResult(name);
# """, [])

View File

@@ -73,7 +73,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = false
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isInCurrentFrame(p, n.sons[0])
else: nil
else: discard
proc openArrayLoc(p: BProc, n: PNode): PRope =
var a: TLoc
@@ -88,7 +88,7 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: InternalError("openArrayLoc: " & typeToString(a.t))
else: internalError("openArrayLoc: " & typeToString(a.t))
proc genArgStringToCString(p: BProc,
n: PNode): PRope {.inline.} =
@@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: PRope): PRope =
result = if r == nil: r else: con(r, ~", ")
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope
@@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ~", ")
template genCallPattern {.dirty.} =
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~", ")
@@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
genAssignment(p, d, list, {}) # no need for deep copying
else:
genCallPattern()
@@ -243,7 +245,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
for i in countup(3, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
InternalError(ri.info, "varargs for objective C method?")
internalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
app(pl, ~" ")

View File

@@ -11,7 +11,7 @@
# -------------------------- constant expressions ------------------------
proc intLiteral(i: biggestInt): PRope =
proc intLiteral(i: BiggestInt): PRope =
if (i > low(int32)) and (i <= high(int32)):
result = toRope(i)
elif i == low(int32):
@@ -22,7 +22,7 @@ proc intLiteral(i: biggestInt): PRope =
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc int32Literal(i: Int): PRope =
proc int32Literal(i: int): PRope =
if i == int(low(int32)):
result = ~"(-2147483647 -1)"
else:
@@ -39,7 +39,7 @@ proc getStrLit(m: BModule, s: string): PRope =
discard cgsym(m, "TGenericSeq")
result = con("TMP", toRope(backendId()))
appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), ToRope(len(s))])
[result, makeCString(s), toRope(len(s))])
proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
@@ -62,7 +62,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
of nkNilLit:
let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure:
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = con("TMP", toRope(id))
if id == gBackendId:
# not found in cache:
@@ -74,7 +74,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
result = toRope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
if skipTypes(ty, abstractVarRange).kind == tyString:
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
if id == gBackendId:
# string literal not found in the cache:
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
@@ -84,9 +84,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
else:
result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit:
result = toRope(n.floatVal.ToStrMaxPrecision)
result = toRope(n.floatVal.toStrMaxPrecision)
else:
InternalError(n.info, "genLiteral(" & $n.kind & ')')
internalError(n.info, "genLiteral(" & $n.kind & ')')
result = nil
proc genLiteral(p: BProc, n: PNode): PRope =
@@ -96,7 +96,7 @@ proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
result = 0
when true:
for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), j * 8)
if j < len(s): result = result or `shl`(ze64(s[j]), j * 8)
else:
# not needed, too complex thinking:
if CPU[platform.hostCPU].endian == CPU[targetCPU].endian:
@@ -117,7 +117,7 @@ proc genRawSetData(cs: TBitSet, size: int): PRope =
else: frmt = "0x$1, "
else:
frmt = "0x$1}$n"
appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))])
appf(result, frmt, [toRope(toHex(ze64(cs[i]), 2))])
else:
result = intLiteral(bitSetToWord(cs, size))
# result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
@@ -127,7 +127,7 @@ proc genSetNode(p: BProc, n: PNode): PRope =
var size = int(getSize(n.typ))
toBitSet(n, cs)
if size > 8:
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = con("TMP", toRope(id))
if id == gBackendId:
# not found in cache:
@@ -155,7 +155,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
of tyVar: result = OnUnknown
of tyPtr: result = OnStack
of tyRef: result = OnHeap
else: InternalError(n.info, "getStorageLoc")
else: internalError(n.info, "getStorageLoc")
of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
result = getStorageLoc(n.sons[0])
else: result = OnUnknown
@@ -202,7 +202,7 @@ proc asgnComplexity(n: PNode): int =
of nkRecList:
for t in items(n):
result += asgnComplexity(t)
else: nil
else: discard
proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
result.k = locField
@@ -242,7 +242,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
optAsgnLoc(src, field.typ, field.loc.r), newflags)
of nkRecList:
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
else: nil
else: discard
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# Consider:
@@ -357,7 +357,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
tyInt..tyUInt64, tyRange, tyVar:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
else: InternalError("genAssignment(" & $ty.kind & ')')
else: internalError("genAssignment: " & $ty.kind)
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
if d.k == locNone: getTemp(p, typ, d)
@@ -403,62 +403,62 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if d.k != locNone: InternalError(e.info, "binaryStmt")
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
if d.k != locNone: internalError(e.info, "binaryStmt")
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
if d.k != locNone: InternalError(e.info, "unaryStmt")
InitLocExpr(p, e.sons[1], a)
if d.k != locNone: internalError(e.info, "unaryStmt")
initLocExpr(p, e.sons[1], a)
lineCg(p, cpsStmts, frmt, [rdLoc(a)])
proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if (d.k != locNone): InternalError(e.info, "binaryStmtChar")
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
if (d.k != locNone): internalError(e.info, "binaryStmtChar")
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)])
proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
proc binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc]))
proc unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a)]))
proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
prc: array[mAddi..mModi64, string] = ["addInt", "subInt", "mulInt",
prc: array[mAddI..mModI64, string] = ["addInt", "subInt", "mulInt",
"divInt", "modInt", "addInt64", "subInt64", "mulInt64", "divInt64",
"modInt64"]
opr: array[mAddi..mModi64, string] = ["+", "-", "*", "/", "%", "+", "-",
opr: array[mAddI..mModI64, string] = ["+", "-", "*", "/", "%", "+", "-",
"*", "/", "%"]
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.typ, abstractRange)
if optOverflowCheck notin p.options:
putIntoDest(p, d, e.typ, ropef("(NI$4)($2 $1 $3)", [toRope(opr[m]),
@@ -466,7 +466,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
else:
var storage: PRope
var size = getSize(t)
if size < platform.IntSize:
if size < platform.intSize:
storage = toRope("NI")
else:
storage = getTypeDesc(p.module, t)
@@ -474,7 +474,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
linefmt(p, cpsLocals, "$1 $2;$n", storage, tmp)
lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n",
tmp, toRope(prc[m]), rdLoc(a), rdLoc(b))
if size < platform.IntSize or t.kind in {tyRange, tyEnum, tySet}:
if size < platform.intSize or t.kind in {tyRange, tyEnum, tySet}:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp]))
@@ -490,7 +490,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
a: TLoc
t: PType
assert(e.sons[1].typ != nil)
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
@@ -556,11 +556,11 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"($1 != $2)"] # Xor
var
a, b: TLoc
s: biggestInt
s: BiggestInt
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ,
@@ -571,8 +571,8 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if a.t.callConv == ccClosure:
putIntoDest(p, d, e.typ,
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
@@ -615,7 +615,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
a: TLoc
t: PType
assert(e.sons[1].typ != nil)
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ,
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
@@ -623,7 +623,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
if mapType(e.sons[0].typ) == ctArray:
if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
expr(p, e.sons[0], d)
@@ -636,21 +636,21 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
d.s = OnUnknown
of tyPtr:
d.s = OnUnknown # BUGFIX!
else: InternalError(e.info, "genDeref " & $a.t.kind)
else: internalError(e.info, "genDeref " & $a.t.kind)
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
var a: TLoc
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, con("&", a.r))
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray:
expr(p, e.sons[0], d)
else:
var a: TLoc
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, addrLoc(a))
template inheritLocation(d: var TLoc, a: TLoc) =
@@ -660,7 +660,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
initLocExpr(p, e.sons[0], a)
if e.sons[1].kind != nkSym: InternalError(e.info, "genRecordFieldAux")
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = a.t
@@ -694,13 +694,13 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var field: PSym = nil
while ty != nil:
if ty.kind notin {tyTuple, tyObject}:
InternalError(e.info, "genRecordField")
internalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = GetUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: InternalError(e.info, "genRecordField 3")
ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
@@ -716,11 +716,11 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
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)
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,
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))
@@ -750,9 +750,9 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genCheckedRecordField")
if field == nil: internalError(e.info, "genCheckedRecordField")
if field.loc.r == nil:
InternalError(e.info, "genCheckedRecordField") # generate the checks:
internalError(e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field)
app(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r)
@@ -766,7 +766,7 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
var first = intLiteral(firstOrd(ty))
# emit range check:
if (optBoundsCheck in p.options):
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
if not isConstExpr(e.sons[1]):
# semantic pass has already checked for const index expressions
if firstOrd(ty) == 0:
@@ -804,13 +804,13 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) =
proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check:
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
if optBoundsCheck in p.options:
if ty.kind == tyString:
linefmt(p, cpsStmts,
@@ -868,7 +868,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe.
discard lists.IncludeStr(p.module.headerFiles, "<stdio.h>")
discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
var args: PRope = nil
var a: TLoc
for i in countup(1, n.len-1):
@@ -877,6 +877,9 @@ proc genEcho(p: BProc, n: PNode) =
linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeatStr(n.len-1, "%s") & tnl), args)
proc gcUsage(n: PNode) =
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
# s = 'Hello ' & name & ', how do you feel?' & 'z'
@@ -902,12 +905,12 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
for i in countup(0, sonsLen(e) - 2):
# compute the length expression:
initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].Typ, abstractVarRange).kind == tyChar:
Inc(L)
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L)
app(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 1].strVal))
inc(L, len(e.sons[i + 1].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
@@ -918,6 +921,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
keepAlive(p, tmp)
else:
genAssignment(p, d, tmp, {needToKeepAlive}) # no need for deep copying
gcUsage(e)
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
@@ -940,13 +944,13 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
for i in countup(0, sonsLen(e) - 3):
# compute the length expression:
initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].Typ, abstractVarRange).kind == tyChar:
Inc(L)
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L)
app(appends, rfmt(p.module, "#appendChar($1, $2);$n",
rdLoc(dest), rdLoc(a)))
else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 2].strVal))
inc(L, len(e.sons[i + 2].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
app(appends, rfmt(p.module, "#appendString($1, $2);$n",
@@ -955,6 +959,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
rdLoc(dest), lens, toRope(L))
keepAlive(p, dest)
app(p.s(cpsStmts), appends)
gcUsage(e)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
@@ -965,20 +970,21 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
var a, b, dest: TLoc
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, seqAppendPattern, [
rdLoc(a),
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
getTypeDesc(p.module, skipTypes(e.sons[2].Typ, abstractVar))])
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
keepAlive(p, a)
initLoc(dest, locExpr, b.t, OnHeap)
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField())
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
gcUsage(e)
proc genReset(p: BProc, n: PNode) =
var a: TLoc
InitLocExpr(p, n.sons[1], a)
initLocExpr(p, n.sons[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
@@ -989,8 +995,8 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
initLoc(b, locExpr, a.t, OnHeap)
if sizeExpr.isNil:
sizeExpr = ropef("sizeof($1)",
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
let args = [getTypeDesc(p.module, reftype),
getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange)))
let args = [getTypeDesc(p.module, refType),
genTypeInfo(p.module, refType),
sizeExpr]
if a.s == OnHeap and usesNativeGC():
@@ -1009,19 +1015,20 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
proc genNew(p: BProc, e: PNode) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
# 'genNew' also handles 'unsafeNew':
if e.len == 3:
var se: TLoc
InitLocExpr(p, e.sons[2], se)
initLocExpr(p, e.sons[2], se)
rawGenNew(p, a, se.rdLoc)
else:
rawGenNew(p, a, nil)
gcUsage(e)
proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqType), length]
genTypeInfo(p.module, seqtype), length]
var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap)
if dest.s == OnHeap and usesNativeGC():
@@ -1037,9 +1044,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
proc genNewSeq(p: BProc, e: PNode) =
var a, b: TLoc
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
genNewSeqAux(p, a, b.rdLoc)
gcUsage(e)
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc
@@ -1051,6 +1059,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
rawGenNew(p, tmp, nil)
t = t.sons[0].skipTypes(abstractInst)
r = ropef("(*$1)", r)
gcUsage(e)
discard getTypeDesc(p.module, t)
for i in 1 .. <e.len:
let it = e.sons[i]
@@ -1062,15 +1071,15 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
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")
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.s = if isRef: OnHeap else: OnStack
tmp2.heapRoot = tmp.r
expr(p, it.sons[1], tmp2)
if d.k == locNone:
@@ -1089,6 +1098,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
arr.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
arr.s = OnHeap # we know that sequences are on the heap
expr(p, t.sons[i], arr)
gcUsage(t)
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
var elem, a, arr: TLoc
@@ -1118,17 +1128,18 @@ proc genNewFinalize(p: BProc, e: PNode) =
ti: PRope
oldModule: BModule
refType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], f)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], f)
initLoc(b, locExpr, a.t, OnHeap)
ti = genTypeInfo(p.module, refType)
appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
ti, getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))])
ti, getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))])
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
bt = skipTypes(refType.sons[0], abstractRange)
genObjectInit(p, cpsStmts, bt, a, false)
gcUsage(e)
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc
@@ -1140,13 +1151,13 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
r = rfmt(nil, "(*$1)", r)
t = skipTypes(t.sons[0], typedescInst)
t = skipTypes(t.lastSon, typedescInst)
if gCmd != cmdCompileToCpp:
while (t.kind == tyObject) and (t.sons[0] != nil):
app(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst)
if isObjLackingTypeField(t):
GlobalError(x.info, errGenerated,
globalError(x.info, errGenerated,
"no 'of' operator available for pure objects")
if nilCheck != nil:
r = rfmt(p.module, "(($1) && #isObj($2.m_type, $3))",
@@ -1162,7 +1173,7 @@ proc genOf(p: BProc, n: PNode, d: var TLoc) =
proc genRepr(p: BProc, e: PNode, d: var TLoc) =
# XXX we don't generate keep alive info for now here
var a: TLoc
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
var t = skipTypes(e.sons[1].typ, abstractVarRange)
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
@@ -1194,7 +1205,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ,
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
else: InternalError(e.sons[0].info, "genRepr()")
else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t))]))
@@ -1206,6 +1217,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]))
gcUsage(e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
var t = skipTypes(e.sons[1].typ, abstractVarRange)
@@ -1213,20 +1225,21 @@ proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, n.sons[1], a)
initLocExpr(p, n.sons[1], a)
a.r = ropecg(p.module, frmt, [rdLoc(a)])
if d.k == locNone: getTemp(p, n.typ, d)
genAssignment(p, d, a, {needToKeepAlive})
gcUsage(n)
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1]
if a.kind == nkHiddenAddr: a = a.sons[0]
var typ = skipTypes(a.Typ, abstractVar)
var typ = skipTypes(a.typ, abstractVar)
case typ.kind
of tyOpenArray, tyVarargs:
if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
else: unaryExpr(p, e, d, "$1Len0")
of tyCstring:
of tyCString:
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
else: unaryExpr(p, e, d, "strlen($1)")
of tyString, tySequence:
@@ -1238,15 +1251,15 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: unaryExpr(p, e, d, "$1->len")
of tyArray, tyArrayConstr:
# YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(Typ)))
if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(typ)))
else: putIntoDest(p, d, e.typ, toRope(lengthOrd(typ)))
else: InternalError(e.info, "genArrayLen()")
else: internalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar)
let setLenPattern = if gCmd != cmdCompileToCpp:
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
@@ -1257,10 +1270,12 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
getTypeDesc(p.module, t.sons[0])])
keepAlive(p, a)
gcUsage(e)
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
keepAlive(P, d)
keepAlive(p, d)
gcUsage(e)
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
# swap(a, b) -->
@@ -1269,8 +1284,8 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
# b = temp
var a, b, tmp: TLoc
getTemp(p, skipTypes(e.sons[1].typ, abstractVar), tmp)
InitLocExpr(p, e.sons[1], a) # eval a
InitLocExpr(p, e.sons[2], b) # eval b
initLocExpr(p, e.sons[1], a) # eval a
initLocExpr(p, e.sons[2], b) # eval b
genAssignment(p, tmp, a, {})
genAssignment(p, a, b, {})
genAssignment(p, b, tmp, {})
@@ -1286,10 +1301,10 @@ proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
proc fewCmps(s: PNode): bool =
# this function estimates whether it is better to emit code
# for constructing the set or generating a bunch of comparisons directly
if s.kind != nkCurly: InternalError(s.info, "fewCmps")
if s.kind != nkCurly: internalError(s.info, "fewCmps")
if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
result = false # it is better to emit the set generation code
elif elemType(s.typ).Kind in {tyInt, tyInt16..tyInt64}:
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
result = true # better not emit the set if int is basetype!
else:
result = sonsLen(s) <= 8 # 8 seems to be a good value
@@ -1308,13 +1323,13 @@ proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
if (e.sons[1].kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons; and if we do
# so, we skip the unnecessary range check: This is a semantical extension
@@ -1328,13 +1343,13 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
b.r = toRope("(")
var length = sonsLen(e.sons[1])
for i in countup(0, length - 1):
if e.sons[1].sons[i].Kind == nkRange:
InitLocExpr(p, e.sons[1].sons[i].sons[0], x)
InitLocExpr(p, e.sons[1].sons[i].sons[1], y)
if e.sons[1].sons[i].kind == nkRange:
initLocExpr(p, e.sons[1].sons[i].sons[0], x)
initLocExpr(p, e.sons[1].sons[i].sons[1], y)
appf(b.r, "$1 >= $2 && $1 <= $3",
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
else:
InitLocExpr(p, e.sons[1].sons[i], x)
initLocExpr(p, e.sons[1].sons[i], x)
appf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
if i < length - 1: app(b.r, " || ")
app(b.r, ")")
@@ -1342,8 +1357,8 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
else:
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
genInExprAux(p, e, a, b, d)
proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
@@ -1356,7 +1371,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"if ($3) $3 = (memcmp($4, $5, $2) != 0);$n",
"&", "|", "& ~", "^"]
var a, b, i: TLoc
var setType = skipTypes(e.sons[1].Typ, abstractVar)
var setType = skipTypes(e.sons[1].typ, abstractVar)
var size = int(getSize(setType))
case size
of 1, 2, 4, 8:
@@ -1391,7 +1406,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
getTemp(p, getSysType(tyInt), i) # our counter
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d)
if d.k == locNone: getTemp(p, getSysType(tyBool), d)
lineF(p, cpsStmts, lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet:
@@ -1421,7 +1436,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
# we use whatever C gives us. Except if we have a value-type, we need to go
# through its address:
var a: TLoc
InitLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[1], a)
let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
putIntoDest(p, d, e.typ, ropef("(*($1*) ($2))",
@@ -1463,13 +1478,13 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
var dest = skipTypes(n.typ, abstractVar)
# range checks for unsigned turned out to be buggy and annoying:
if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
InitLocExpr(p, n.sons[0], a)
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, ropef("(($1) ($2))",
[getTypeDesc(p.module, dest), rdCharLoc(a)]))
else:
InitLocExpr(p, n.sons[0], a)
initLocExpr(p, n.sons[0], a)
if leValue(n.sons[2], n.sons[1]):
InternalError(n.info, "range check will always fail; empty range")
internalError(n.info, "range check will always fail; empty range")
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
@@ -1492,6 +1507,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar),
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]))
gcUsage(n)
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
var x: TLoc
@@ -1511,17 +1527,17 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
binaryExpr(p, e, d, "#eqStrings($1, $2)")
proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if {optNanCheck, optInfCheck} * p.options != {}:
if {optNaNCheck, optInfCheck} * p.options != {}:
const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"]
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
toRope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ)))
if optNanCheck in p.options:
if optNaNCheck in p.options:
linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
if optInfCheck in p.options:
linefmt(p, cpsStmts, "#infCheck($1);$n", rdLoc(d))
@@ -1537,30 +1553,30 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
of mShrI..mXor: binaryArith(p, e, d, op)
of mEqProc: genEqProc(p, e, d)
of mAddi..mModi64: binaryArithOverflow(p, e, d, op)
of mAddI..mModI64: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mSwap: genSwap(p, e, d)
of mUnaryLt:
if not (optOverflowCheck in p.Options): unaryExpr(p, e, d, "$1 - 1")
if not (optOverflowCheck in p.options): unaryExpr(p, e, d, "$1 - 1")
else: unaryExpr(p, e, d, "#subInt($1, 1)")
of mPred:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, e, d, "$1 - $2")
if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 - $2")
else: binaryExpr(p, e, d, "#subInt($1, $2)")
of mSucc:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, e, d, "$1 + $2")
if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 + $2")
else: binaryExpr(p, e, d, "#addInt($1, $2)")
of mInc:
if not (optOverflowCheck in p.Options):
if not (optOverflowCheck in p.options):
binaryStmt(p, e, d, "$1 += $2;$n")
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
else:
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
of ast.mDec:
if not (optOverflowCheck in p.Options):
if not (optOverflowCheck in p.options):
binaryStmt(p, e, d, "$1 -= $2;$n")
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
@@ -1623,7 +1639,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap)
if id == gBackendId:
# expression not found in the cache:
@@ -1699,14 +1715,14 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
[rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
expr(p, it, rec)
proc IsConstClosure(n: PNode): bool {.inline.} =
proc isConstClosure(n: PNode): bool {.inline.} =
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
n.sons[1].kind == nkNilLit
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
assert n.kind == nkClosure
if IsConstClosure(n):
if isConstClosure(n):
inc(p.labels)
var tmp = con("LOC", toRope(p.labels))
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
@@ -1751,7 +1767,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
r = ropef("(*$1)", [r])
t = skipTypes(t.sons[0], abstractInst)
t = skipTypes(t.lastSon, abstractInst)
if gCmd != cmdCompileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
app(r, ".Sup")
@@ -1790,7 +1806,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var tmp = con("TMP", toRope(id))
if id == gBackendId:
@@ -1808,7 +1824,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
case n.kind
of nkSym:
var sym = n.sym
case sym.Kind
case sym.kind
of skMethod:
if sym.getBody.kind == nkEmpty or sfDispatcher in sym.flags:
# we cannot produce code for the dispatcher yet:
@@ -1817,10 +1833,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else:
genProc(p.module, sym)
putLocIntoDest(p, d, sym.loc)
of skProc, skConverter, skIterator:
of skProc, skConverter, skIterators:
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(n.info, "expr: proc not init " & sym.name.s)
internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skConst:
if sfFakeConst in sym.flags:
@@ -1835,9 +1851,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of skVar, skForVar, skResult, skLet:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(n.info, "expr: var not init " & sym.name.s)
internalError(n.info, "expr: var not init " & sym.name.s)
if sfThread in sym.flags:
AccessThreadLocalVar(p, sym)
accessThreadLocalVar(p, sym)
if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
else:
@@ -1846,13 +1862,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
putLocIntoDest(p, d, sym.loc)
of skTemp:
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(n.info, "expr: temp not init " & sym.name.s)
internalError(n.info, "expr: temp not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skParam:
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(n.info, "expr: param not init " & sym.name.s)
internalError(n.info, "expr: param not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
else: InternalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
of nkNilLit:
if not isEmptyType(n.typ):
putIntoDest(p, d, n.typ, genLiteral(p, n))
@@ -1901,14 +1917,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkHiddenAddr, nkAddr: genAddr(p, n, d)
of nkBracketExpr:
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr: genArrayElem(p, n, d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d)
of tySequence, tyString: genSeqElem(p, n, d)
of tyCString: genCStringElem(p, n, d)
of tyTuple: genTupleElem(p, n, d)
else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d)
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
@@ -1928,12 +1944,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var sym = n.sons[namePos].sym
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(n.info, "expr: proc not init " & sym.name.s)
internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of nkClosure: genClosure(p, n, d)
of nkMetaNode: expr(p, n.sons[0], d)
of nkEmpty: nil
of nkEmpty: discard
of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection: genConstStmt(p, n)
@@ -1963,7 +1978,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef:
nil
discard
of nkPragma: genPragma(p, n)
of nkProcDef, nkMethodDef, nkConverterDef:
if (n.sons[genericParamsPos].kind == nkEmpty):
@@ -1984,7 +1999,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkState: genState(p, n)
of nkGotoState: genGotoState(p, n)
of nkBreakState: genBreakState(p, n)
else: InternalError(n.info, "expr(" & $n.kind & "); unknown node kind")
else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode): PRope =
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
@@ -2022,7 +2037,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result])
proc genConstExpr(p: BProc, n: PNode): PRope =
case n.Kind
case n.kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genConstExpr(p, n.sons[1])
of nkCurly:

View File

@@ -108,7 +108,7 @@ proc genMergeInfo*(m: BModule): PRope =
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" hasframe:")
encodeVInt(ord(m.FrameDeclared), s)
encodeVInt(ord(m.frameDeclared), s)
s.add(tnl)
s.add("*/")
result = s.toRope
@@ -119,8 +119,8 @@ proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
@@ -129,8 +129,8 @@ proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
@@ -145,33 +145,6 @@ proc atEndMark(buf: cstring, pos: int): bool =
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len
when false:
proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
result = newMutableRope(30_000)
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
buf = L.buf
result.data.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
buf = L.buf
result.data.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
inc pos, NimMergeEndMark.len
break
result.data.add(buf[pos])
inc pos
L.bufpos = pos
freezeMutableRope(result)
proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
@@ -179,15 +152,15 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
pos = nimlexbase.handleCR(L, pos)
buf = L.buf
r.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
pos = nimlexbase.handleLF(L, pos)
buf = L.buf
r.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
internalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
@@ -208,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'
proc NewFakeType(id: int): PType =
proc newFakeType(id: int): PType =
new(result)
result.id = id
@@ -224,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
# XXX little hack: we create a "fake" type object with the correct Id
# better would be to adapt the data structure to not even store the
# object as key, but only the Id
IdTablePut(result, newFakeType(key), value.toRope)
idTablePut(result, newFakeType(key), value.toRope)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
@@ -249,14 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo": readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: InternalError("ccgmerge: unkown key: " & k)
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: internalError("ccgmerge: unkown key: " & k)
when not defined(nimhygiene):
{.pragma: inject.}
template withCFile(cfilename: string, body: stmt) {.immediate.} =
var s = LLStreamOpen(cfilename, fmRead)
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer
openBaseLexer(L, s)
@@ -285,7 +258,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
nil
discard
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
# read back into section
@@ -300,9 +273,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
InternalError("ccgmerge: unknown section: " & k)
internalError("ccgmerge: unknown section: " & k)
else:
InternalError("ccgmerge: '*/' expected")
internalError("ccgmerge: '*/' expected")
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
@@ -323,4 +296,3 @@ proc mergeFiles*(cfilename: string, m: BModule) =
m.s[i] = con(old.f[i], m.s[i])
for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = con(old.p[i], m.initProc.s(i))

View File

@@ -16,7 +16,7 @@ const
# above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) =
if gSelectedGc in {gcMarkAndSweep, gcGenerational} and
if gSelectedGC in {gcMarkAndSweep, gcGenerational} and
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
@@ -26,7 +26,7 @@ proc registerGcRoot(p: BProc, v: PSym) =
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
var L = sonsLen(n)
genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup)
@@ -45,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else:
if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = ropef("$1.$2",
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
@@ -62,9 +62,10 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
lineCg(p, cpsStmts, start, args)
inc(p.labels)
result = len(p.blocks)
setlen(p.blocks, result + 1)
setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope)
@@ -81,7 +82,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
let topBlock = p.blocks.len-1
# the block is merged into the parent block
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
setlen(p.blocks, topBlock)
setLen(p.blocks, topBlock)
# this is done after the block is popped so $n is
# properly indented when pretty printing is enabled
line(p, cpsStmts, blockEnd)
@@ -126,7 +127,7 @@ proc genGotoState(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.BeforeRetNeeded = true
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
for i in 0 .. lastOrd(n.sons[0].typ):
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
@@ -137,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) =
if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code!
initLocExpr(p, n.sons[0].sons[1], a)
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)])
lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
else:
initLocExpr(p, n.sons[0], a)
# the environment is guaranteed to contain the 'state' field at offset 0:
@@ -200,7 +201,7 @@ proc genConstStmt(p: BProc, t: PNode) =
for i in countup(0, sonsLen(t) - 1):
var it = t.sons[i]
if it.kind == nkCommentStmt: continue
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
var c = it.sons[0].sym
if c.typ.containsCompileTimeOnly: continue
if sfFakeConst in c.flags:
@@ -232,71 +233,91 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
# Lend:
var
a: TLoc
Lelse: TLabel
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
getTemp(p, n.typ, d)
genLineDir(p, n)
let Lend = getLabel(p)
let lend = getLabel(p)
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.len == 2:
when newScopeForIf: startBlock(p)
initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p)
lelse = getLabel(p)
inc(p.labels)
lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
[rdLoc(a), Lelse, toRope(p.labels)])
[rdLoc(a), lelse, toRope(p.labels)])
when not newScopeForIf: startBlock(p)
expr(p, it.sons[1], d)
endBlock(p)
if sonsLen(n) > 1:
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [Lend])
fixLabel(p, Lelse)
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
fixLabel(p, lelse)
elif it.len == 1:
startBlock(p)
expr(p, it.sons[0], d)
endBlock(p)
else: internalError(n.info, "genIf()")
if sonsLen(n) > 1: fixLabel(p, Lend)
if sonsLen(n) > 1: fixLabel(p, lend)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts,
proc blockLeaveActions(p: BProc, howMany: int) =
var L = p.nestedTryStmts.len
# danger of endless recursion! we workaround this here by a temp stack
var stack: seq[PNode]
newSeq(stack, howMany)
for i in countup(1, howMany):
stack[i-1] = p.nestedTryStmts[L-i]
setLen(p.nestedTryStmts, L-howMany)
newSeq(stack, 0)
var alreadyPoppedCnt = p.inExceptBlock
for tryStmt in items(stack):
for i in countup(1, howManyTrys):
if gCmd != cmdCompileToCpp:
# Pop safe points generated by try
if alreadyPoppedCnt > 0:
dec alreadyPoppedCnt
else:
linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step.
var tryStmt = p.nestedTryStmts.pop
stack.add(tryStmt)
# Find finally-stmt for this try-stmt
# and generate a copy of its sons
var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howMany-1, 0):
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if gCmd != cmdCompileToCpp:
for i in countdown(p.inExceptBlock-1, 0):
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
linefmt(p, cpsStmts, "#popCurrentException();$n")
proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlock)
if (p.finallySafePoints.len > 0):
# If we're in a finally block, and we came here by exception
# consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
proc genComputedGoto(p: BProc; n: PNode) =
# first pass: Generate array of computed labels:
var casePos = -1
var arraySize: Int
var arraySize: int
for i in 0 .. <n.len:
let it = n.sons[i]
if it.kind == nkCaseStmt:
@@ -322,8 +343,20 @@ proc genComputedGoto(p: BProc; n: PNode) =
gotoArray.appf("&&TMP$#, ", (id+i).toRope)
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
line(p, cpsLocals, gotoArray)
let topBlock = p.blocks.len-1
let oldBody = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
let tailB = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
let tailA = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA)
let caseStmt = n.sons[casePos]
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
@@ -340,8 +373,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
genStmts(p, it.lastSon)
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
app(p.s(cpsStmts), tailB)
app(p.s(cpsStmts), tailA)
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
@@ -352,7 +388,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
# significantly worse code
var
a: TLoc
Labl: TLabel
labl: TLabel
assert(sonsLen(t) == 2)
inc(p.withinLoop)
genLineDir(p, t)
@@ -366,7 +402,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
var loopBody = t.sons[1]
if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[ccompiler].props:
hasComputedGoto in CC[cCompiler].props:
# for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1]
@@ -401,7 +437,7 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(P, forLoopVar)
assignLocalVar(p, forLoopVar)
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
@@ -433,9 +469,11 @@ proc genBreakStmt(p: BProc, t: PNode) =
# an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
InternalError(t.info, "no loop to break")
internalError(t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label])
@@ -454,7 +492,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty:
var a: TLoc
InitLocExpr(p, t.sons[0], a)
initLocExpr(p, t.sons[0], a)
var e = rdLoc(a)
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t)
@@ -484,16 +522,16 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel =
var Lend = getLabel(p)
var lend = getLabel(p)
for i in 1..until:
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d)
lineF(p, cpsStmts, "goto $1;$n", [Lend])
lineF(p, cpsStmts, "goto $1;$n", [lend])
else:
exprBlock(p, t.sons[i].sons[0], d)
result = Lend
result = lend
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr,
@@ -520,8 +558,8 @@ proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr) =
var a: TLoc
initLocExpr(p, t.sons[0], a)
var Lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, Lend)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[PRope]) =
@@ -565,25 +603,25 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements
var Lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, Lend)
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend)
else:
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
for i in countup(0, sonsLen(b)-2):
# last son is block
if (b.sons[i].Kind == nkRange) and
if (b.sons[i].kind == nkRange) and
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
return true
proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
for i in 1..n.len-1:
var branch = n[i]
var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
result = i
elif hasSwitchRange notin CC[ccompiler].props:
elif hasSwitchRange notin CC[cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i
@@ -591,7 +629,7 @@ proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len
for j in 0 .. length-2:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[ccompiler].props:
if hasSwitchRange in CC[cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
@@ -599,18 +637,18 @@ proc genCaseRange(p: BProc, branch: PNode) =
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
Inc(v.intVal)
inc(v.intVal)
else:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement:
var splitPoint = IfSwitchSplitPoint(p, n)
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n.sons[0], a)
var Lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
splitPoint, a) else: nil
@@ -629,10 +667,10 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n")
if (hasAssume in CC[ccompiler].props) and not hasDefault:
if (hasAssume in CC[cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n")
lineF(p, cpsStmts, "}$n")
if Lend != nil: fixLabel(p, Lend)
if lend != nil: fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
@@ -691,7 +729,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
expr(p, t.sons[0], d)
length = sonsLen(t)
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
if optStackTrace in p.Options:
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
i = 1
@@ -764,7 +802,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
#
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
discard lists.IncludeStr(p.module.headerFiles, "<setjmp.h>")
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName()
discard cgsym(p.module, "E_Base")
@@ -779,7 +817,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
endBlock(p)
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.Options:
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
var i = 1
@@ -812,18 +850,20 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.nestedTryStmts)
endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally:
p.finallySafePoints.add(safePoint)
exprBlock(p, t.sons[i].sons[0], d)
discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
var res = ""
for i in countup(0, sonsLen(t) - 1):
case t.sons[i].Kind
case t.sons[i].kind
of nkStrLit..nkTripleStrLit:
res.add(t.sons[i].strVal)
of nkSym:
var sym = t.sons[i].sym
if sym.kind in {skProc, skIterator, skMethod}:
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
var a: TLoc
initLocExpr(p, t.sons[i], a)
res.add(rdLoc(a).ropeToStr)
@@ -835,9 +875,9 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
r = mangleName(sym)
sym.loc.r = r # but be consequent!
res.add(r.ropeToStr)
else: InternalError(t.sons[i].info, "genAsmOrEmitStmt()")
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
if isAsmStmt and hasGnuAsm in CC[ccompiler].props:
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
for x in splitLines(res):
var j = 0
while x[j] in {' ', '\t'}: inc(j)
@@ -858,9 +898,9 @@ proc genAsmStmt(p: BProc, t: PNode) =
var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
if p.prc == nil:
# top level asm statement?
appf(p.module.s[cfsProcHeaders], CC[ccompiler].asmStmtFrmt, [s])
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
else:
lineF(p, cpsStmts, CC[ccompiler].asmStmtFrmt, [s])
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t)
@@ -877,7 +917,7 @@ var
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
if optEndb in p.Options:
if optEndb in p.options:
if t.kind == nkExprColonExpr:
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal)
@@ -891,7 +931,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) =
if optEndb notin p.Options: return
if optEndb notin p.options: return
var a: TLoc
initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
@@ -905,7 +945,7 @@ proc genPragma(p: BProc, n: PNode) =
case whichPragma(it)
of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it)
of wWatchpoint: genWatchpoint(p, it)
of wWatchPoint: genWatchpoint(p, it)
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
@@ -913,7 +953,7 @@ proc genPragma(p: BProc, n: PNode) =
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn.sons[0]
if le.kind == nkCheckedFieldExpr:
@@ -929,7 +969,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
assert t.kind == tyObject
discard genTypeInfo(p.module, t)
var L = lengthOrd(field.typ)
if not ContainsOrIncl(p.module.declaredThings, field.id):
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))
lineCg(p, cpsStmts,
@@ -942,7 +982,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var dotExpr = e.sons[0]
var d: PSym
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
getTemp(p, a.t, tmp)
expr(p, e.sons[1], tmp)
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
@@ -950,9 +990,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
if not FieldDiscriminantCheckNeeded(p, e):
if not fieldDiscriminantCheckNeeded(p, e):
var a: TLoc
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy)
assert(a.t != nil)
loadInto(p, e.sons[0], e.sons[1], a)
@@ -962,4 +1002,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
expr(p, t, a)
InternalAssert a.k in {locNone, locTemp, locLocalVar}
internalAssert a.k in {locNone, locTemp, locLocalVar}

View File

@@ -16,8 +16,8 @@ proc emulatedThreadVars(): bool =
result = {optThreads, optTlsEmulation} <= gGlobalOptions
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.ThreadVarAccessed:
p.ThreadVarAccessed = true
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
p.module.usesThreadVars = true
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
app(p.procSec(cpsInit),
@@ -55,7 +55,7 @@ proc generateThreadLocalStorage(m: BModule) =
for t in items(nimtvDeps): discard getTypeDesc(m, t)
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
proc GenerateThreadVarsSize(m: BModule) =
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
app(m.s[cfsProcs],
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)

View File

@@ -28,7 +28,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
genTraverseProc(c, accessor, n.sons[i])
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
@@ -74,7 +74,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
genTraverseProc(c, accessor.parentObj, typ.sons[i])
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple:
let typ = GetUniqueType(typ)
let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence:
@@ -83,7 +83,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
else:
nil
discard
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var p = c.p
@@ -111,7 +111,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p
assert typ.kind != tyTypedesc
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ)
else:

View File

@@ -25,7 +25,7 @@ proc mangleField(name: string): string =
of 'A'..'Z':
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
of '_':
nil
discard
of 'a'..'z', '0'..'9':
add(result, name[i])
else:
@@ -48,7 +48,7 @@ proc mangle(name: string): string =
of 'A'..'Z':
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
of '_':
nil
discard
of 'a'..'z', '0'..'9':
add(result, name[i])
else:
@@ -69,14 +69,14 @@ proc mangleName(s: PSym): PRope =
if result == nil:
if gCmd == cmdCompileToLLVM:
case s.kind
of skProc, skMethod, skConverter, skConst, skIterator:
of skProc, skMethod, skConverter, skConst, skIterators:
result = ~"@"
of skVar, skForVar, skResult, skLet:
if sfGlobal in s.flags: result = ~"@"
else: result = ~"%"
of skTemp, skParam, skType, skEnumField, skModule:
result = ~"%"
else: InternalError(s.info, "mangleName")
else: internalError(s.info, "mangleName")
when oKeepVariableNames:
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
@@ -150,7 +150,7 @@ proc getTypeName(typ: PType): PRope =
typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope)
else: con([~"%", typ.typeName, typ.id.toRope])
result = typ.loc.r
if result == nil: InternalError("getTypeName: " & $typ.kind)
if result == nil: internalError("getTypeName: " & $typ.kind)
proc mapSetType(typ: PType): TCTypeKind =
case int(getSize(typ))
@@ -183,9 +183,9 @@ proc mapType(typ: PType): TCTypeKind =
else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef:
var base = skipTypes(typ.sons[0], typedescInst)
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
else: result = ctPtr
of tyPointer: result = ctPtr
of tySequence: result = ctNimSeq
@@ -194,7 +194,7 @@ proc mapType(typ: PType): TCTypeKind =
of tyCString: result = ctCString
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
else: InternalError("mapType")
else: internalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
@@ -229,11 +229,11 @@ const
"stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline",
"$1 noinline", "fastcc $1", "ccc $1", "$1"]
proc CacheGetType(tab: TIdTable, key: PType): PRope =
proc cacheGetType(tab: TIdTable, key: PType): PRope =
# returns nil if we need to declare this type
# since types are now unique via the ``GetUniqueType`` mechanism, this slow
# linear search is not necessary anymore:
result = PRope(IdTableGet(tab, key))
result = PRope(idTableGet(tab, key))
proc getTempName(): PRope =
result = rfmt(nil, "TMP$1", toRope(backendId()))
@@ -246,7 +246,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
assert skResult != s.kind
if tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.Kind
case pt.kind
of tyObject:
if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
result = true # requested anyway
@@ -262,14 +262,14 @@ proc ccgIntroducedPtr(s: PSym): bool =
proc fillResult(param: PSym) =
fillLoc(param.loc, locParam, param.typ, ~"Result",
OnStack)
if (mapReturnType(param.typ) != ctArray) and IsInvalidReturnType(param.typ):
if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
when false:
if t.Kind in {tyRef, tyPtr, tyVar}:
var b = skipTypes(t.sons[0], typedescInst)
var b = skipTypes(t.lastson, typedescInst)
if b.kind == tySet and mapSetType(b) == ctArray:
return getTypeDescAux(m, b, check)
result = getTypeDescAux(m, t, check)
@@ -288,7 +288,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
else:
rettype = getTypeDescAux(m, t.sons[0], check)
for i in countup(1, sonsLen(t.n) - 1):
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
if params != nil: app(params, ~", ")
@@ -305,7 +305,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
var arr = param.typ
if arr.kind == tyVar: arr = arr.sons[0]
var j = 0
while arr.Kind in {tyOpenArray, tyVarargs}:
while arr.kind in {tyOpenArray, tyVarargs}:
# this fixes the 'sort' bug:
if param.typ.kind == tyVar: param.loc.s = OnUnknown
# need to pass hidden parameter:
@@ -344,7 +344,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
"NI", "NI8", "NI16", "NI32", "NI64",
"NF", "NF32", "NF64", "NF128",
"NU", "NU8", "NU16", "NU32", "NU64",]
case typ.Kind
case typ.kind
of tyPointer:
result = typeNameOrLiteral(typ, "void*")
of tyEnum:
@@ -362,12 +362,12 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyString:
discard cgsym(m, "NimStringDesc")
result = typeNameOrLiteral(typ, "NimStringDesc*")
of tyCstring: result = typeNameOrLiteral(typ, "NCSTRING")
of tyCString: result = typeNameOrLiteral(typ, "NCSTRING")
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil
@@ -375,14 +375,17 @@ proc getTypePre(m: BModule, typ: PType): PRope =
if typ == nil: result = toRope("void")
else:
result = getSimpleTypeDesc(m, typ)
if result == nil: result = CacheGetType(m.typeCache, typ)
if result == nil: result = cacheGetType(m.typeCache, typ)
proc structOrUnion(t: PType): PRope =
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
proc getForwardStructFormat(): string =
if gCmd == cmdCompileToCpp: result = "struct $1;$n"
else: result = "typedef struct $1 $1;$n"
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n"
proc getTypeForward(m: BModule, typ: PType): PRope =
result = CacheGetType(m.forwTypeCache, typ)
result = cacheGetType(m.forwTypeCache, typ)
if result != nil: return
result = getTypePre(m, typ)
if result != nil: return
@@ -390,9 +393,10 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
of tySequence, tyTuple, tyObject:
result = getTypeName(typ)
if not isImportedType(typ):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, typ, result)
else: InternalError("getTypeForward(" & $typ.kind & ')')
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')')
proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
if (rectype.sym != nil) and
@@ -400,7 +404,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
result = field.loc.r
else:
result = toRope(mangleField(field.name.s))
if result == nil: InternalError(field.info, "mangleRecFieldName")
if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: PRope, rectype: PType,
@@ -415,7 +419,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
for i in countup(0, sonsLen(n) - 1):
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genRecordFieldsAux")
if (n.sons[0].kind != nkSym): internalError(n.info, "genRecordFieldsAux")
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
@@ -445,7 +449,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
let fieldType = field.loc.t
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname])
else:
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
@@ -455,23 +464,33 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
# declare the record:
var hasField = false
var attribute: PRope =
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
else: nil
result = ropecg(m, CC[ccompiler].structStmtFmt,
[structOrUnion(typ), name, attribute])
if typ.kind == tyObject:
if typ.sons[0] == nil:
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
result = ropecg(m, "struct $1 {$n", [name])
appcg(m, result, " {$n", [])
else:
result = ropecg(m, "struct $1 {$n#TNimType* m_type;$n", [name])
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
hasField = true
elif gCmd == cmdCompileToCpp:
result = ropecg(m, "struct $1 : public $2 {$n",
[name, getTypeDescAux(m, typ.sons[0], check)])
appcg(m, result, " : public $1 {$n",
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
else:
result = ropecg(m, "struct $1 {$n $2 Sup;$n",
[name, getTypeDescAux(m, typ.sons[0], check)])
appcg(m, result, " {$n $1 Sup;$n",
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
else:
result = ropef("struct $1 {$n", [name])
appf(result, " {$n", [name])
var desc = getRecordFields(m, typ, check)
if (desc == nil) and not hasField:
appf(result, "char dummy;$n", [])
@@ -480,8 +499,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
app(result, "};" & tnl)
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
result = ropef("struct $1 {$n", [name])
check: var TIntSet): PRope =
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
var desc: PRope = nil
for i in countup(0, sonsLen(typ) - 1):
appf(desc, "$1 Field$2;$n",
@@ -497,49 +516,49 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
# returns only the type's name
var
name, rettype, desc, recdesc: PRope
n: biggestInt
n: BiggestInt
t, et: PType
t = getUniqueType(typ)
if t == nil: InternalError("getTypeDescAux: t == nil")
if t == nil: internalError("getTypeDescAux: t == nil")
if t.sym != nil: useHeader(m, t.sym)
result = getTypePre(m, t)
if result != nil: return
if ContainsOrIncl(check, t.id):
InternalError("cannot generate C type for: " & typeToString(typ))
if containsOrIncl(check, t.id):
internalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow.
case t.Kind
case t.kind
of tyRef, tyPtr, tyVar:
et = getUniqueType(t.sons[0])
et = getUniqueType(t.lastSon)
if et.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
# this is correct! sets have no proper base type, so we treat
# ``var set[char]`` in `getParamTypeDesc`
et = getUniqueType(elemType(et))
case et.Kind
case et.kind
of tyObject, tyTuple:
# no restriction! We have a forward declaration for structs
name = getTypeForward(m, et)
result = con(name, "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
pushType(m, et)
of tySequence:
# no restriction! We have a forward declaration for structs
name = getTypeForward(m, et)
result = con(name, "**")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
pushType(m, et)
else:
# else we have a strong dependency :-(
result = con(getTypeDescAux(m, et, check), "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs:
et = getUniqueType(t.sons[0])
result = con(getTypeDescAux(m, et, check), "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
of tyProc:
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
genProcParams(m, t, rettype, desc, check)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
@@ -553,14 +572,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
of tySequence:
# we cannot use getTypeForward here because then t would be associated
# with the name of the struct, not with the pointer to the struct:
result = CacheGetType(m.forwTypeCache, t)
result = cacheGetType(m.forwTypeCache, t)
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result)
assert(CacheGetType(m.typeCache, t) == nil)
IdTablePut(m.typeCache, t, con(result, "*"))
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
assert(cacheGetType(m.typeCache, t) == nil)
idTablePut(m.typeCache, t, con(result, "*"))
if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const
@@ -579,18 +599,19 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
if n <= 0:
n = 1 # make an array of at least one element
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
appf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
[getTypeDescAux(m, t.sons[1], check), result, ToRope(n)])
[getTypeDescAux(m, t.sons[1], check), result, toRope(n)])
of tyObject, tyTuple:
result = CacheGetType(m.forwTypeCache, t)
result = cacheGetType(m.forwTypeCache, t)
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result)
IdTablePut(m.typeCache, t, result) # always call for sideeffects:
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
idTablePut(m.typeCache, t, result) # always call for sideeffects:
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
else: recdesc = getTupleDesc(m, t, result, check)
if not isImportedType(t): app(m.s[cfsTypes], recdesc)
@@ -602,7 +623,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
of 8: result = toRope("NU64")
else:
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
[result, toRope(getSize(t))])
@@ -610,7 +631,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
tyIter, tyTypeDesc:
result = getTypeDescAux(m, lastSon(t), check)
else:
InternalError("getTypeDescAux(" & $t.kind & ')')
internalError("getTypeDescAux(" & $t.kind & ')')
result = nil
# fixes bug #145:
excl(check, t.id)
@@ -737,10 +758,10 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
var objtype = objtype
while lookupInRecord(objtype.n, d.name) == nil:
objtype = objtype.sons[0]
if objType.sym == nil:
InternalError(d.info, "anonymous obj with discriminator")
if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [
toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
toRope(objtype.sym.name.s.mangle), toRope(d.name.s.mangle)])
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
discard cgsym(m, "TNimNode")
@@ -911,7 +932,7 @@ include ccgtrav
proc genTypeInfo(m: BModule, t: PType): PRope =
var t = getUniqueType(t)
result = ropef("NTI$1", [toRope(t.id)])
if ContainsOrIncl(m.typeInfoMarker, t.id):
if containsOrIncl(m.typeInfoMarker, t.id):
return con("(&".toRope, result, ")".toRope)
let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
@@ -948,8 +969,8 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')
result = con("(&".toRope, result, ")".toRope)
proc genTypeSection(m: BModule, n: PNode) =
nil
discard

View File

@@ -22,19 +22,19 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
of nkPragma:
for i in 0 .. < n.len:
if whichPragma(n[i]) == w: return n[i]
else: nil
else: discard
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
proc hashString*(s: string): biggestInt =
proc hashString*(s: string): BiggestInt =
# has to be the same algorithm as system.hashString!
if CPU[targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
var b = 0'i64
for i in countup(0, len(s) - 1):
b = b +% Ord(s[i])
b = b +% ord(s[i])
b = b +% `shl`(b, 10)
b = b xor `shr`(b, 6)
b = b +% `shl`(b, 3)
@@ -44,7 +44,7 @@ proc hashString*(s: string): biggestInt =
else:
var a = 0'i32
for i in countup(0, len(s) - 1):
a = a +% Ord(s[i]).int32
a = a +% ord(s[i]).int32
a = a +% `shl`(a, 10'i32)
a = a xor `shr`(a, 6'i32)
a = a +% `shl`(a, 3'i32)
@@ -57,7 +57,7 @@ var
gCanonicalTypes: array[TTypeKind, PType]
proc initTypeTables() =
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
proc resetCaches* =
## XXX: fix that more properly
@@ -70,7 +70,7 @@ when false:
for i in countup(low(TTypeKind), high(TTypeKind)):
echo i, " ", gTypeTable[i].counter
proc GetUniqueType*(key: PType): PType =
proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler!
if key == nil: return
var k = key.kind
@@ -86,12 +86,12 @@ proc GetUniqueType*(key: PType): PType =
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClasses:
InternalError("value expected, but got a type")
of tyGenericParam:
InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key))
of tyTypeDesc, tyTypeClasses, tyGenericParam,
tyFromExpr, tyFieldAccessor:
internalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
tyConst, tyIter, tyStatic:
result = getUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
@@ -102,51 +102,50 @@ proc GetUniqueType*(key: PType): PType =
# we have to do a slow linear search because types may need
# to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyObject:
if tfFromGeneric notin key.flags:
# fast case; lookup per id suffices:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
else:
# ugly slow case: need to compare by structure
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyProc:
# tyVar is not 100% correct, but would speeds things up a little:
if key.callConv != ccClosure:
result = key
else:
# ugh, we need the canon here:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
proc TableGetType*(tab: TIdTable, key: PType): PObject =
proc tableGetType*(tab: TIdTable, key: PType): PObject =
# returns nil if we need to declare this type
result = IdTableGet(tab, key)
result = idTableGet(tab, key)
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
@@ -169,7 +168,7 @@ proc makeLLVMString*(s: string): PRope =
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
app(result, toRope(res))
setlen(res, 0)
setLen(res, 0)
case s[i]
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
add(res, '\\')
@@ -178,4 +177,4 @@ proc makeLLVMString*(s: string): PRope =
add(res, "\\00\"")
app(result, toRope(res))
InitTypeTables()
initTypeTables()

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -52,7 +52,7 @@ proc emitLazily(s: PSym): bool {.inline.} =
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.k = k
result.s = s
result.t = GetUniqueType(typ)
result.t = getUniqueType(typ)
result.r = nil
result.a = - 1
result.flags = {}
@@ -75,12 +75,12 @@ proc isSimpleConst(typ: PType): bool =
proc useStringh(m: BModule) =
if not m.includesStringh:
m.includesStringh = true
discard lists.IncludeStr(m.headerFiles, "<string.h>")
discard lists.includeStr(m.headerFiles, "<string.h>")
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.Flags:
if lfHeader in sym.loc.flags:
assert(sym.annex != nil)
discard lists.IncludeStr(m.headerFiles, getStr(sym.annex.path))
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
proc cgsym(m: BModule, name: string): PRope
@@ -103,7 +103,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j
@@ -116,7 +116,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
of 'N':
app(result, rnl)
inc(i)
else: InternalError("ropes: invalid format string $" & frmt[i])
else: internalError("ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
inc(i)
var j = i
@@ -128,7 +128,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
inc(i, 2)
var j = 0
while frmt[i] in Digits:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
app(result, cgsym(m, args[j-1].ropeToStr))
var start = i
@@ -194,7 +194,7 @@ when compileTimeRopeFmt:
if i - 1 >= start:
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
macro rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
## Experimental optimized rope-formatting operator
## The run-time code it produces will be very fast, but will it speed up
## the compilation of nimrod itself or will the macro execution time
@@ -209,7 +209,7 @@ when compileTimeRopeFmt:
of ffParam:
result.add(args[frag.intValue])
else:
template rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
@@ -279,11 +279,11 @@ proc genLineDir(p: BProc, t: PNode) =
if optEmbedOrigSrc in gGlobalOptions:
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "#endb($1, $2);$n",
line.toRope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.Options ==
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "nimln($1, $2);$n",
@@ -319,7 +319,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
takeAddr: bool) =
case analyseObjectWithTypeField(t)
of frNone:
nil
discard
of frHeader:
var r = rdLoc(a)
if not takeAddr: r = ropef("(*$1)", [r])
@@ -351,7 +351,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack)
initLoc(nilLoc, locTemp, loc.t, OnStack)
nilLoc.r = toRope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
@@ -513,7 +513,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
include ccgthreadvars
proc VarInDynamicLib(m: BModule, sym: PSym)
proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): PRope
proc assignGlobalVar(p: BProc, s: PSym) =
@@ -522,8 +522,8 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
if q != nil and not ContainsOrIncl(q.declaredThings, s.id):
VarInDynamicLib(q, s)
if q != nil and not containsOrIncl(q.declaredThings, s.id):
varInDynamicLib(q, s)
else:
s.loc.r = mangleDynLibProc(s)
return
@@ -578,7 +578,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc intLiteral(i: biggestInt): PRope
proc intLiteral(i: BiggestInt): PRope
proc genLiteral(p: BProc, n: PNode): PRope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
@@ -610,7 +610,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
if gVerbosity >= 2:
MsgWriteln("Dependency: " & lib.path.strVal)
msgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil
for i in countup(0, high(s)):
inc(m.labels)
@@ -632,7 +632,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: InternalError("loadDynamicLib")
if lib.name == nil: internalError("loadDynamicLib")
proc mangleDynLibProc(sym: PSym): PRope =
if sfCompilerProc in sym.flags:
@@ -641,7 +641,7 @@ proc mangleDynLibProc(sym: PSym): PRope =
else:
result = ropef("Dl_$1", [toRope(sym.id)])
proc SymInDynamicLib(m: BModule, sym: PSym) =
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
let isCall = isGetProcAddr(lib)
var extname = sym.loc.r
@@ -665,14 +665,14 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1]
InternalAssert(last.kind == nkStrLit)
internalAssert(last.kind == nkStrLit)
let idx = last.strVal
if idx.len == 0:
app(m.initProc.s(cpsStmts), load)
elif idx.len == 1 and idx[0] in {'0'..'9'}:
app(m.extensionLoaders[idx[0]], load)
else:
InternalError(sym.info, "wrong index: " & idx)
internalError(sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
@@ -682,7 +682,7 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
"$1 = linkonce global $2 zeroinitializer$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc VarInDynamicLib(m: BModule, sym: PSym) =
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
var extname = sym.loc.r
loadDynamicLib(m, lib)
@@ -697,7 +697,7 @@ proc VarInDynamicLib(m: BModule, sym: PSym) =
appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc SymInDynamicLibPartial(m: BModule, sym: PSym) =
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
@@ -705,10 +705,10 @@ proc cgsym(m: BModule, name: string): PRope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter, skIterator: genProc(m, sym)
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("cgsym: " & name)
else: internalError("cgsym: " & name)
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
@@ -724,7 +724,7 @@ proc generateHeaders(m: BModule) =
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
else:
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
@@ -747,7 +747,7 @@ proc closureSetup(p: BProc, prc: PSym) =
# prc.ast[paramsPos].last contains the type we're after:
var ls = lastSon(prc.ast[paramsPos])
if ls.kind != nkSym:
InternalError(prc.info, "closure generation failed")
internalError(prc.info, "closure generation failed")
var env = ls.sym
#echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, env)
@@ -761,6 +761,8 @@ proc genProcAux(m: BModule, prc: PSym) =
var returnStmt: PRope = nil
assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
internalError(prc.info, "proc has no result symbol")
var res = prc.ast.sons[resultPos].sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
@@ -784,7 +786,7 @@ proc genProcAux(m: BModule, prc: PSym) =
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: PRope
if sfPure in prc.flags:
if hasNakedDeclspec in extccomp.CC[extccomp.ccompiler].props:
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
header = con("__declspec(naked) ", header)
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
@@ -793,7 +795,7 @@ proc genProcAux(m: BModule, prc: PSym) =
app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals))
var procname = CStringLit(p, generatedProc, prc.name.s)
var procname = cstringLit(p, generatedProc, prc.name.s)
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else:
app(generatedProc, p.s(cpsLocals))
@@ -811,16 +813,16 @@ proc genProcAux(m: BModule, prc: PSym) =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.Flags: return
if lfDynamicLib in sym.loc.Flags:
if lfNoDecl in sym.loc.flags: return
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not ContainsOrIncl(m.declaredThings, sym.id):
not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
elif not ContainsOrIncl(m.declaredProtos, sym.id):
elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym)
if sfPure in sym.flags and hasNakedAttribute in CC[ccompiler].props:
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
header.app(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
@@ -832,21 +834,21 @@ proc genProcNoForward(m: BModule, prc: PSym) =
discard cgsym(m, prc.name.s)
return
genProcPrototype(m, prc)
if lfNoDecl in prc.loc.Flags: nil
if lfNoDecl in prc.loc.flags: discard
elif prc.typ.callConv == ccInline:
# We add inline procs to the calling module to enable C based inlining.
# This also means that a check with ``q.declaredThings`` is wrong, we need
# a check for ``m.declaredThings``.
if not ContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
SymInDynamicLib(q, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
else:
SymInDynamicLibPartial(m, prc)
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
genProcAux(q, prc)
proc requestConstImpl(p: BProc, sym: PSym) =
@@ -854,15 +856,15 @@ proc requestConstImpl(p: BProc, sym: PSym) =
useHeader(m, sym)
if sym.loc.k == locNone:
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
if lfNoDecl in sym.loc.Flags: return
if lfNoDecl in sym.loc.flags: return
# declare implementation:
var q = findPendingModule(m, sym)
if q != nil and not ContainsOrIncl(q.declaredThings, sym.id):
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
assert q.initProc.module == q
appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
# declare header:
if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
[getTypeDesc(m, sym.loc.t), sym.loc.r])
@@ -879,17 +881,17 @@ proc genProc(m: BModule, prc: PSym) =
else:
genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not ContainsOrIncl(generatedHeader.declaredThings, prc.id):
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags)
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
if (lfNoDecl in sym.loc.Flags) or ContainsOrIncl(m.declaredThings, sym.id):
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
@@ -911,29 +913,29 @@ proc addIntTypes(result: var PRope) {.inline.} =
appf(result, "#define NIM_INTBITS $1", [
platform.CPU[targetCPU].intSize.toRope])
proc getCopyright(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n" &
"/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n" &
"; Compiled for: $2, $3, $4$n" &
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.ccompiler].name),
proc getCopyright(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; (c) 2014 Andreas Rumpf$N" &
"; Compiled for: $2, $3, $4$N" &
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.cCompiler].name),
toRope(getCompileCFileCmd(cfilenoext))])
proc getFileHeader(cfilenoext: string): PRope =
proc getFileHeader(cfilenoext: string): PRope =
result = getCopyright(cfilenoext)
addIntTypes(result)
@@ -941,46 +943,72 @@ 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)
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
proc genMainProc(m: BModule) =
proc genMainProc(m: BModule) =
const
CommonMainBody =
"\tsystemDatInit();$n" &
"\tsystemInit();$n" &
PreMainBody =
"\tsystemDatInit();$N" &
"\tsystemInit();$N" &
"$1" &
"$2" &
"$3" &
"$4"
MainProcs =
"\tNimMain();$N"
MainProcsWithResult =
MainProcs & "\treturn nim_program_result;$N"
NimMainBody =
"N_CDECL(void, NimMain)(void) {$N" &
"\tPreMain();$N" &
"$1" &
"$2" &
"$3" &
"$4"
PosixNimMain =
"int cmdCount;$n" &
"char** cmdLine;$n" &
"char** gEnv;$n" &
"N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
"\tcmdLine = args;$n" & "\tcmdCount = argc;$n" & "\tgEnv = env;$n" &
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
StandaloneCMain = "int main(void) {$n" &
"\tNimMain();$n" &
"\treturn 0;$n" & "}$n"
WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
" HINSTANCE hPrevInstance, $n" &
" LPSTR lpCmdLine, int nCmdShow) {$n" &
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
" LPVOID lpvReserved) {$n" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) NimMain();$n" &
"\treturn 1;$n" & "}$n"
"}$N$N"
PosixNimMain =
"int cmdCount;$N" &
"char** cmdLine;$N" &
"char** gEnv;$N" &
NimMainBody
PosixCMain =
"int main(int argc, char** args, char** env) {$N" &
"\tcmdLine = args;$N" &
"\tcmdCount = argc;$N" &
"\tgEnv = env;$N" &
MainProcsWithResult &
"}$N$N"
StandaloneCMain =
"int main(void) {$N" &
MainProcs &
"\treturn 0;$N" &
"}$N$N"
WinNimMain = NimMainBody
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
" HINSTANCE hPrevInstance, $N" &
" LPSTR lpCmdLine, int nCmdShow) {$N" &
MainProcsWithResult & "}$N$N"
WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
" LPVOID lpvReserved) {$N" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$n" &
"\tNimMain();$n}$n"
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
MainProcs &
"}$N$N"
var nimMain, otherMain: TFormatStr
if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
@@ -990,10 +1018,10 @@ proc genMainProc(m: BModule) =
else:
nimMain = WinNimDllMain
otherMain = WinCDllMain
discard lists.IncludeStr(m.headerFiles, "<windows.h>")
discard lists.includeStr(m.headerFiles, "<windows.h>")
elif optGenDynLib in gGlobalOptions:
nimMain = posixNimDllMain
otherMain = posixCDllMain
nimMain = PosixNimDllMain
otherMain = PosixCDllMain
elif platform.targetOS == osStandalone:
nimMain = PosixNimMain
otherMain = StandaloneCMain
@@ -1006,16 +1034,20 @@ proc genMainProc(m: BModule) =
let initStackBottomCall = if emulatedThreadVars() or
platform.targetOS == osStandalone: "".toRope
else: ropecg(m, "\t#initStackBottom();$n")
else: ropecg(m, "\t#initStackBottom();$N")
inc(m.labels)
appcg(m, m.s[cfsProcs], nimMain, [mainDatInit, initStackBottomCall,
gBreakpoints, mainModInit, toRope(m.labels)])
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
if optNoMain notin gGlobalOptions:
appcg(m, m.s[cfsProcs], otherMain, [])
proc getSomeInitName(m: PSym, suffix: string): PRope =
assert m.kind == skModule
assert m.owner.kind == skPackage
if {sfSystemModule, sfMainModule} * m.flags == {}:
result = m.info.toFullPath.getPackageName.mangle.toRope
result = m.owner.name.s.mangle.toRope
result.app m.name.s
result.app suffix
@@ -1030,13 +1062,17 @@ proc registerModuleToMain(m: PSym) =
"declare void $1() noinline$N", [init])
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
"declare void $1() noinline$N", [datInit])
if not (sfSystemModule in m.flags):
appff(mainModInit, "\t$1();$n", "call void ()* $1$n", [init])
appff(mainDatInit, "\t$1();$n", "call void ()* $1$n", [datInit])
if sfSystemModule notin m.flags:
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
if sfMainModule in m.flags:
app(mainModInit, initCall)
else:
app(otherModsInit, initCall)
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [initname])
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
@@ -1053,12 +1089,12 @@ proc genInitCode(m: BModule) =
app(prc, m.postInitProc.s(cpsLocals))
app(prc, genSectionEnd(cpsLocals))
if optStackTrace in m.initProc.options and not m.FrameDeclared:
if optStackTrace in m.initProc.options and not m.frameDeclared:
# BUT: the generated init code might depend on a current frame, so
# declare it nevertheless:
m.FrameDeclared = true
if not m.PreventStackTrace:
var procname = CStringLit(m.initProc, prc, m.module.name.s)
m.frameDeclared = true
if not m.preventStackTrace:
var procname = cstringLit(m.initProc, prc, m.module.name.s)
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
app(prc, ~"\tTFrame F; F.len = 0;$N")
@@ -1074,12 +1110,12 @@ proc genInitCode(m: BModule) =
app(prc, m.initProc.s(cpsStmts))
app(prc, m.postInitProc.s(cpsStmts))
app(prc, genSectionEnd(cpsStmts))
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
if optStackTrace in m.initProc.options and not m.preventStackTrace:
app(prc, deinitFrame(m.initProc))
app(prc, deinitGCFrame(m.initProc))
appf(prc, "}$N$N")
prc.appff("N_NOINLINE(void, $1)(void) {$n",
prc.appff("N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit:
@@ -1127,7 +1163,7 @@ proc initProcOptions(m: BModule): TOptions =
proc rawNewModule(module: PSym, filename: string): BModule =
new(result)
InitLinkedList(result.headerFiles)
initLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
result.declaredProtos = initIntSet()
result.cfilename = filename
@@ -1148,7 +1184,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
# no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags:
result.PreventStackTrace = true
result.preventStackTrace = true
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
@@ -1156,10 +1192,10 @@ proc nullify[T](arr: var T) =
for i in low(arr)..high(arr):
arr[i] = nil
proc resetModule*(m: var BModule) =
proc resetModule*(m: BModule) =
# between two compilations in CAAS mode, we can throw
# away all the data that was written to disk
InitLinkedList(m.headerFiles)
initLinkedList(m.headerFiles)
m.declaredProtos = initIntSet()
initIdTable(m.forwTypeCache)
m.initProc = newProc(nil, m)
@@ -1171,7 +1207,7 @@ proc resetModule*(m: var BModule) =
m.forwardedProcs = @[]
m.typeNodesName = getTempName()
m.nimTypesName = getTempName()
m.PreventStackTrace = sfSystemModule in m.module.flags
m.preventStackTrace = sfSystemModule in m.module.flags
nullify m.s
m.usesThreadVars = false
m.typeNodes = 0
@@ -1202,7 +1238,7 @@ proc rawNewModule(module: PSym): BModule =
proc newModule(module: PSym): BModule =
# we should create only one cgen module for each module sym
InternalAssert getCgenModule(module) == nil
internalAssert getCgenModule(module) == nil
result = rawNewModule(module)
growCache gModules, module.position
@@ -1210,7 +1246,7 @@ proc newModule(module: PSym): BModule =
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
InternalError("added pending module twice: " & module.filename)
internalError("added pending module twice: " & module.filename)
proc myOpen(module: PSym): PPassContext =
result = newModule(module)
@@ -1263,19 +1299,19 @@ proc finishModule(m: BModule) =
# a ``for`` loop here
var prc = m.forwardedProcs[i]
if sfForward in prc.flags:
InternalError(prc.info, "still forwarded: " & prc.name.s)
internalError(prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc)
inc(i)
assert(gForwardedProcsCounter >= i)
dec(gForwardedProcsCounter, i)
setlen(m.forwardedProcs, 0)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfilenoext)
if writeRopeIfNotEqual(code, cfile): return
if ExistsFile(objFile) and os.FileNewer(objFile, cfile): result = false
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
else:
writeRope(code, cfile)
@@ -1296,7 +1332,7 @@ proc writeModule(m: BModule, pending: bool) =
if sfMainModule in m.module.flags:
# generate main file:
app(m.s[cfsProcHeaders], mainModProcs)
GenerateThreadVarsSize(m)
generateThreadVarsSize(m)
var code = genModule(m, cfilenoext)
when hasTinyCBackend:
@@ -1313,7 +1349,7 @@ proc writeModule(m: BModule, pending: bool) =
var code = genModule(m, cfilenoext)
writeRope(code, cfile)
addFileToCompile(cfilenoext)
elif not ExistsFile(toObjFile(cfilenoext)):
elif not existsFile(toObjFile(cfilenoext)):
# Consider: first compilation compiles ``system.nim`` and produces
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:

View File

@@ -41,7 +41,8 @@ type
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
ctFloat, ctFloat32, ctFloat64, ctFloat128,
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
@@ -57,17 +58,20 @@ type
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
# using return in finally statements
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
breakIdx*: int # the block that will be exited
@@ -78,7 +82,7 @@ type
maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
gcFrameId*: natural # for the GC stack marking
gcFrameId*: Natural # for the GC stack marking
gcFrameType*: PRope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType]
@@ -86,9 +90,9 @@ type
module*: PSym
filename*: string
s*: TCFileSections # sections of the C file
PreventStackTrace*: bool # true if stack traces need to be prevented
preventStackTrace*: bool # true if stack traces need to be prevented
usesThreadVars*: bool # true if the module uses a thread var
FrameDeclared*: bool # hack for ROD support so that we don't declare
frameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile*: bool # C source file is the header file
includesStringh*: bool # C source file already includes ``<string.h>``
@@ -108,13 +112,14 @@ type
forwardedProcs*: TSymSeq # keep forwarded procs here
typeNodes*, nimTypes*: int # used for type info generation
typeNodesName*, nimTypesName*: PRope # used for type info generation
labels*: natural # for generating unique module-scope names
labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', PRope] # special procs for the
# OpenGL wrapper
injectStmt*: PRope
var
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
# varuious parts of the main module
gMapping*: PRope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
@@ -139,8 +144,9 @@ proc newProc*(prc: PSym, module: BModule): BProc =
else: result.options = gOptions
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
iterator cgenModules*: var BModule =
iterator cgenModules*: BModule =
for i in 0..high(gModules):
# ultimately, we are iterating over the file ids here.
# some "files" won't have an associated cgen module (like stdin)

View File

@@ -18,16 +18,16 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var source = skipTypes(n.typ, abstractPtrs)
if (source.kind == tyObject) and (dest.kind == tyObject):
var diff = inheritanceDiff(dest, source)
if diff == high(int): InternalError(n.info, "cgmeth.genConv")
if diff == high(int): internalError(n.info, "cgmeth.genConv")
if diff < 0:
result = newNodeIT(nkObjUpConv, n.info, d)
addSon(result, n)
if downCast: InternalError(n.info, "cgmeth.genConv: no upcast allowed")
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, d)
addSon(result, n)
if not downCast:
InternalError(n.info, "cgmeth.genConv: no downcast allowed")
if not downcast:
internalError(n.info, "cgmeth.genConv: no downcast allowed")
else:
result = n
else:
@@ -59,14 +59,14 @@ proc sameMethodBucket(a, b: PSym): bool =
aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {tyGenericInst})
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
aa = aa.sons[0]
bb = bb.sons[0]
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(aa, bb) or
(aa.kind == tyObject) and (bb.kind == tyObject) and
(inheritanceDiff(bb, aa) < 0):
nil
discard
else:
return
result = true
@@ -112,12 +112,12 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
if t.kind == tyObject:
for i in countup(1, high(methods)):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t):
if not sameType(t2, t):
return true
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
for col in countup(1, sonsLen(a.typ) - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb)
@@ -126,14 +126,14 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
# we use shellsort here; fast and simple
var N = len(a)
var n = len(a)
var h = 1
while true:
h = 3 * h + 1
if h > N: break
if h > n: break
while true:
h = h div 3
for i in countup(h, N - 1):
for i in countup(h, n - 1):
var v = a[i]
var j = i
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
@@ -154,7 +154,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in countup(1, paramLen - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
addSon(isn, newSymNode(iss))
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
@@ -195,7 +195,7 @@ proc generateMethodDispatchers*(): PNode =
for bucket in countup(0, len(gMethods) - 1):
var relevantCols = initIntSet()
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
if relevantCol(gMethods[bucket], col): incl(relevantCols, col)
sortBucket(gMethods[bucket], relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -21,40 +21,40 @@ type
passCmd2, # second pass over the command line
passPP # preprocessor called ProcessCommand()
proc ProcessCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
proc processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
# implementation
const
HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]\n" &
"Copyright (c) 2004-2013 by Andreas Rumpf\n"
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
const
Usage = slurp"doc/basicopt.txt".replace("//", "")
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
proc getCommandLineDesc(): string =
result = (HelpMessage % [VersionAsString, platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]) & Usage
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & Usage
proc HelpOnError(pass: TCmdLinePass) =
proc helpOnError(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(getCommandLineDesc())
msgWriteln(getCommandLineDesc())
quit(0)
proc writeAdvancedUsage(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(`%`(HelpMessage, [VersionAsString,
platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]) & AdvancedUsage)
msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & AdvancedUsage)
quit(0)
proc writeVersionInfo(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(`%`(HelpMessage, [VersionAsString,
platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]))
msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]))
quit(0)
var
@@ -62,16 +62,16 @@ var
proc writeCommandLineUsage() =
if not helpWritten:
MsgWriteln(getCommandLineDesc())
msgWriteln(getCommandLineDesc())
helpWritten = true
proc addPrefix(switch: string): string =
if len(switch) == 1: result = "-" & switch
else: result = "--" & switch
proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": LocalError(info, errInvalidCmdLineOption, "-")
else: LocalError(info, errInvalidCmdLineOption, addPrefix(switch))
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
info: TLineInfo) =
@@ -86,29 +86,29 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
inc(i)
if i >= len(switch): arg = ""
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
else: InvalidCmdLineOption(pass, switch, info)
else: invalidCmdLineOption(pass, switch, info)
proc ProcessOnOffSwitch(op: TOptions, arg: string, pass: TCmdlinePass,
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case whichKeyword(arg)
of wOn: gOptions = gOptions + op
of wOff: gOptions = gOptions - op
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc ProcessOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdlinePass,
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case whichKeyword(arg)
of wOn: gGlobalOptions = gGlobalOptions + op
of wOff: gGlobalOptions = gGlobalOptions - op
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc ExpectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": LocalError(info, errCmdLineArgExpected, addPrefix(switch))
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": LocalError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
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) =
var id = "" # arg = "X]:on|off"
var i = 0
@@ -117,21 +117,21 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
add(id, arg[i])
inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
if state == wHint:
var x = findStr(msgs.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin))
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
else:
var x = findStr(msgs.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
case whichKeyword(substr(arg, i))
of wOn: incl(gNotes, n)
of wOff: excl(gNotes, n)
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processCompile(filename: string) =
var found = findFile(filename)
@@ -150,14 +150,14 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
of "markandsweep": result = gSelectedGC == gcMarkAndSweep
of "generational": result = gSelectedGC == gcGenerational
of "none": result = gSelectedGC == gcNone
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "opt":
case arg.normalize
of "speed": result = contains(gOptions, optOptimizeSpeed)
of "size": result = contains(gOptions, optOptimizeSize)
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: InvalidCmdLineOption(passCmd1, switch, info)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: invalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -173,11 +173,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "linetrace": result = contains(gOptions, optLineTrace)
of "debugger": result = contains(gOptions, optEndb)
of "profiler": result = contains(gOptions, optProfiler)
of "checks", "x": result = gOptions * checksOptions == checksOptions
of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
of "floatchecks":
result = gOptions * {optNanCheck, optInfCheck} == {optNanCheck, optInfCheck}
result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
of "infchecks": result = contains(gOptions, optInfCheck)
of "nanchecks": result = contains(gOptions, optNanCheck)
of "nanchecks": result = contains(gOptions, optNaNCheck)
of "objchecks": result = contains(gOptions, optObjCheck)
of "fieldchecks": result = contains(gOptions, optFieldCheck)
of "rangechecks": result = contains(gOptions, optRangeCheck)
@@ -194,7 +194,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
of "patterns": result = contains(gOptions, optPatterns)
else: InvalidCmdLineOption(passCmd1, switch, info)
else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or
@@ -202,20 +202,20 @@ proc processPath(path: string, notRelativeToProj = false): string =
path
else:
options.gProjectPath / path
result = UnixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
proc trackDirty(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 4: LocalError(info, errTokenExpected,
if a.len != 4: localError(info, errTokenExpected,
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
var line, column: int
if parseUtils.parseInt(a[2], line) <= 0:
LocalError(info, errInvalidNumber, a[1])
localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[3], column) <= 0:
LocalError(info, errInvalidNumber, a[2])
localError(info, errInvalidNumber, a[2])
gDirtyBufferIdx = a[0].fileInfoIdx
gDirtyOriginalIdx = a[1].fileInfoIdx
@@ -225,21 +225,21 @@ proc trackDirty(arg: string, info: TLineInfo) =
proc track(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
var line, column: int
if parseUtils.parseInt(a[1], line) <= 0:
LocalError(info, errInvalidNumber, a[1])
localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[2], column) <= 0:
LocalError(info, errInvalidNumber, a[2])
localError(info, errInvalidNumber, a[2])
optTrackPos = newLineInfo(a[0], line, column)
msgs.addCheckpoint(optTrackPos)
proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
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
theOS: TSystemOS
cpu: TSystemCPU
@@ -259,23 +259,26 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "excludepath":
expectArg(switch, arg, pass, info)
let path = processPath(arg)
lists.ExcludeStr(options.searchPaths, path)
lists.ExcludeStr(options.lazyPaths, path)
lists.excludeStr(options.searchPaths, path)
lists.excludeStr(options.lazyPaths, path)
of "nimcache":
expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg)
of "out", "o":
expectArg(switch, arg, pass, info)
options.outFile = arg
of "docseesrcurl":
expectArg(switch, arg, pass, info)
options.docSeeSrcUrl = arg
of "mainmodule", "m":
expectArg(switch, arg, pass, info)
optMainModule = arg
of "define", "d":
expectArg(switch, arg, pass, info)
DefineSymbol(arg)
defineSymbol(arg)
of "undef", "u":
expectArg(switch, arg, pass, info)
UndefSymbol(arg)
undefSymbol(arg)
of "compile":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: processCompile(arg)
@@ -308,7 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
case arg.normalize
of "boehm":
gSelectedGC = gcBoehm
DefineSymbol("boehmgc")
defineSymbol("boehmgc")
of "refc":
gSelectedGC = gcRefc
of "v2":
@@ -322,42 +325,42 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "none":
gSelectedGC = gcNone
defineSymbol("nogc")
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": ProcessOnOffSwitch({optWarns}, arg, pass, info)
of "warning": ProcessSpecificNote(arg, wWarning, pass, info)
of "hint": ProcessSpecificNote(arg, wHint, pass, info)
of "hints": ProcessOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": ProcessOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": ProcessOnOffSwitch({optStackTrace}, arg, pass, info)
of "linetrace": ProcessOnOffSwitch({optLineTrace}, arg, pass, info)
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
of "warning": processSpecificNote(arg, wWarning, pass, info)
of "hint": processSpecificNote(arg, wHint, pass, info)
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
of "debugger":
ProcessOnOffSwitch({optEndb}, arg, pass, info)
if optEndb in gOptions: DefineSymbol("endb")
else: UndefSymbol("endb")
processOnOffSwitch({optEndb}, arg, pass, info)
if optEndb in gOptions: defineSymbol("endb")
else: undefSymbol("endb")
of "profiler":
ProcessOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: DefineSymbol("profiler")
else: UndefSymbol("profiler")
of "checks", "x": ProcessOnOffSwitch(checksOptions, arg, pass, info)
processOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: defineSymbol("profiler")
else: undefSymbol("profiler")
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
of "floatchecks":
ProcessOnOffSwitch({optNanCheck, optInfCheck}, arg, pass, info)
of "infchecks": ProcessOnOffSwitch({optInfCheck}, arg, pass, info)
of "nanchecks": ProcessOnOffSwitch({optNanCheck}, arg, pass, info)
of "objchecks": ProcessOnOffSwitch({optObjCheck}, arg, pass, info)
of "fieldchecks": ProcessOnOffSwitch({optFieldCheck}, arg, pass, info)
of "rangechecks": ProcessOnOffSwitch({optRangeCheck}, arg, pass, info)
of "boundchecks": ProcessOnOffSwitch({optBoundsCheck}, arg, pass, info)
of "overflowchecks": ProcessOnOffSwitch({optOverflowCheck}, arg, pass, info)
of "linedir": ProcessOnOffSwitch({optLineDir}, arg, pass, info)
of "assertions", "a": ProcessOnOffSwitch({optAssert}, arg, pass, info)
of "deadcodeelim": ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info)
of "tlsemulation": ProcessOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": ProcessOnOffSwitchG({optTaintMode}, arg, pass, info)
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads": processOnOffSwitchG({optThreads}, arg, pass, info)
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
of "implicitstatic":
ProcessOnOffSwitch({optImplicitStatic}, arg, pass, info)
processOnOffSwitch({optImplicitStatic}, arg, pass, info)
of "patterns":
ProcessOnOffSwitch({optPatterns}, arg, pass, info)
processOnOffSwitch({optPatterns}, arg, pass, info)
of "opt":
expectArg(switch, arg, pass, info)
case arg.normalize
@@ -370,7 +373,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
of "app":
expectArg(switch, arg, pass, info)
case arg.normalize
@@ -392,7 +395,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
excl(gGlobalOptions, optGenGuiApp)
defineSymbol("library")
defineSymbol("staticlib")
else: LocalError(info, errGuiConsoleOrLibExpectedButXFound, arg)
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
of "passc", "t":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
@@ -401,18 +404,18 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cIncludes.add arg
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
of "clibdir":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLibs.add arg
if pass in {passCmd2, passPP}: cLibs.add arg.processPath
of "clib":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
of "header":
headerFile = arg
incl(gGlobalOptions, optGenIndex)
of "index":
ProcessOnOffSwitchG({optGenIndex}, arg, pass, info)
processOnOffSwitchG({optGenIndex}, arg, pass, info)
of "import":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: implicitImports.add arg
@@ -428,19 +431,19 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "os":
expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}:
theOS = platform.NameToOS(arg)
if theOS == osNone: LocalError(info, errUnknownOS, arg)
theOS = platform.nameToOS(arg)
if theOS == osNone: localError(info, errUnknownOS, arg)
elif theOS != platform.hostOS:
setTarget(theOS, targetCPU)
condsyms.InitDefines()
condsyms.initDefines()
of "cpu":
expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}:
cpu = platform.NameToCPU(arg)
if cpu == cpuNone: LocalError(info, errUnknownCPU, arg)
cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(info, errUnknownCPU, arg)
elif cpu != platform.hostCPU:
setTarget(targetOS, cpu)
condsyms.InitDefines()
condsyms.initDefines()
of "run", "r":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optRun)
@@ -460,7 +463,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
expectNoArg(switch, arg, pass, info)
helpOnError(pass)
of "symbolfiles":
ProcessOnOffSwitchG({optSymbolFiles}, arg, pass, info)
processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
of "skipcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipConfigFile)
@@ -520,13 +523,13 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
case arg
of "partial": idents.firstCharIsCS = true
of "none": idents.firstCharIsCS = false
else: LocalError(info, errGenerated,
else: localError(info, errGenerated,
"'partial' or 'none' expected, but found " & arg)
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: InvalidCmdLineOption(pass, switch, info)
else: invalidCmdLineOption(pass, switch, info)
proc ProcessCommand(switch: string, pass: TCmdLinePass) =
proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo)

View File

@@ -16,10 +16,10 @@ import
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: PStringTable
proc DefineSymbol*(symbol: string) =
proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"
proc UndefSymbol*(symbol: string) =
proc undefSymbol*(symbol: string) =
gSymbols[symbol] = "false"
proc isDefined*(symbol: string): bool =
@@ -37,52 +37,53 @@ proc countDefinedSymbols*(): int =
for key, val in pairs(gSymbols):
if val == "true": inc(result)
proc InitDefines*() =
proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
DefineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code:
DefineSymbol("nimhygiene")
DefineSymbol("niminheritable")
DefineSymbol("nimmixin")
DefineSymbol("nimeffects")
DefineSymbol("nimbabel")
DefineSymbol("nimcomputedgoto")
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
defineSymbol("nimmixin")
defineSymbol("nimeffects")
defineSymbol("nimbabel")
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
# add platform specific symbols:
case targetCPU
of cpuI386: DefineSymbol("x86")
of cpuIa64: DefineSymbol("itanium")
of cpuAmd64: DefineSymbol("x8664")
of cpuI386: defineSymbol("x86")
of cpuIa64: defineSymbol("itanium")
of cpuAmd64: defineSymbol("x8664")
else: discard
case targetOS
of osDOS:
DefineSymbol("msdos")
of osDos:
defineSymbol("msdos")
of osWindows:
DefineSymbol("mswindows")
DefineSymbol("win32")
of osLinux, osMorphOS, osSkyOS, osIrix, osPalmOS, osQNX, osAtari, osAix,
defineSymbol("mswindows")
defineSymbol("win32")
of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix,
osHaiku:
# these are all 'unix-like'
DefineSymbol("unix")
DefineSymbol("posix")
defineSymbol("unix")
defineSymbol("posix")
of osSolaris:
DefineSymbol("sunos")
DefineSymbol("unix")
DefineSymbol("posix")
of osNetBSD, osFreeBSD, osOpenBSD:
DefineSymbol("unix")
DefineSymbol("bsd")
DefineSymbol("posix")
of osMacOS:
DefineSymbol("macintosh")
of osMacOSX:
DefineSymbol("macintosh")
DefineSymbol("unix")
DefineSymbol("posix")
defineSymbol("sunos")
defineSymbol("unix")
defineSymbol("posix")
of osNetbsd, osFreebsd, osOpenbsd:
defineSymbol("unix")
defineSymbol("bsd")
defineSymbol("posix")
of osMacos:
defineSymbol("macintosh")
of osMacosx:
defineSymbol("macintosh")
defineSymbol("unix")
defineSymbol("posix")
else: discard
DefineSymbol("cpu" & $cpu[targetCPU].bit)
DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian]))
DefineSymbol(cpu[targetCPU].name)
DefineSymbol(platform.os[targetOS].name)
defineSymbol("cpu" & $CPU[targetCPU].bit)
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
defineSymbol(CPU[targetCPU].name)
defineSymbol(platform.OS[targetOS].name)
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
DefineSymbol("emulatedthreadvars")
defineSymbol("emulatedthreadvars")

View File

@@ -18,8 +18,8 @@ const
InitAdler32* = int32(1)
proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
proc updateCrc32*(val: Char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: Pointer, length: int): TCrc32
proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: pointer, length: int): TCrc32
proc strCrc32*(s: string): TCrc32
proc crcFromFile*(filename: string): TCrc32
proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
@@ -75,10 +75,10 @@ const
755167117]
proc updateCrc32(val: int8, crc: TCrc32): TCrc32 =
result = TCrc32(crc32Table[(int(crc) xor (int(val) and 0x000000FF)) and
result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
0x000000FF]) xor (crc shr TCrc32(8))
proc updateCrc32(val: Char, crc: TCrc32): TCrc32 =
proc updateCrc32(val: char, crc: TCrc32): TCrc32 =
result = updateCrc32(toU8(ord(val)), crc)
proc strCrc32(s: string): TCrc32 =
@@ -93,7 +93,7 @@ type
TByteArray = array[0..10000000, int8]
PByteArray = ref TByteArray
proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
proc crcFromBuf(buf: pointer, length: int): TCrc32 =
var p = cast[PByteArray](buf)
result = InitCrc32
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
@@ -102,11 +102,11 @@ proc crcFromFile(filename: string): TCrc32 =
const
bufSize = 8000 # don't use 8K for the memory allocator!
var
bin: tfile
bin: TFile
result = InitCrc32
if not open(bin, filename):
return # not equal if file does not exist
var buf = alloc(BufSize)
var buf = alloc(bufSize)
var p = cast[PByteArray](buf)
while true:
var readBytes = readBuffer(bin, buf, bufSize)

View File

@@ -39,11 +39,11 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
else:
nil
discard
proc generateDot(project: string) =
writeRope(ropef("digraph $1 {$n$2}$n", [
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
changeFileExt(project, "dot"))
proc myOpen(module: PSym): PPassContext =

View File

@@ -14,7 +14,7 @@
import
ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2, json
importer, sempass2, json, xmltree, cgi, typesrenderer
type
TSections = array[TSymKind, PRope]
@@ -23,8 +23,9 @@ type
id: int # for generating IDs
toc, section: TSections
indexValFilename: string
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
PDoc* = ref TDocumentor
PDoc* = ref TDocumentor ## Alias to type less.
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
@@ -40,33 +41,40 @@ proc compilerMsgHandler(filename: string, line, col: int,
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
GlobalError(newLineInfo(filename, line, col), k, arg)
globalError(newLineInfo(filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} =
result = options.findFile(s)
if result.len == 0:
result = getCurrentDir() / s
if not existsFile(result): result = ""
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
rstOptions: TRstParseOptions): PRstNode =
result = rstParse(text, filename, line, column, hasToc, rstOptions,
options.FindFile, compilerMsgHandler)
docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
new(result)
initRstGenerator(result[], (if gCmd != cmdRst2Tex: outHtml else: outLatex),
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
options.gConfigVars, filename, {roSupportRawDirective},
options.FindFile, compilerMsgHandler)
docgenFindFile, compilerMsgHandler)
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
if gCmd != cmdRst2Tex: appf(dest, xml, args)
proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
if gCmd != cmdRst2tex: appf(dest, xml, args)
else: appf(dest, tex, args)
proc getVarIdx(varnames: openarray[string], id: string): int =
proc getVarIdx(varnames: openArray[string], id: string): int =
for i in countup(0, high(varnames)):
if cmpIgnoreStyle(varnames[i], id) == 0:
return i
result = -1
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
varvalues: openarray[PRope]): PRope =
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
varvalues: openArray[PRope]): PRope =
var i = 0
var L = len(frmt)
result = nil
@@ -85,7 +93,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
@@ -112,7 +120,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx])
else: rawMessage(errUnkownSubstitionVar, id)
else: InternalError("ropeFormatNamedVars")
else: internalError("ropeFormatNamedVars")
var start = i
while i < L:
if frmt[i] != '$': inc(i)
@@ -124,7 +132,7 @@ proc genComment(d: PDoc, n: PNode): string =
var dummyHasToc: bool
if n.comment != nil and startsWith(n.comment, "##"):
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLineNumber(n.info), toColumn(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}), result)
proc genRecComment(d: PDoc, n: PNode): PRope =
@@ -138,6 +146,23 @@ proc genRecComment(d: PDoc, n: PNode): PRope =
else:
n.comment = nil
proc getPlainDocstring(n: PNode): string =
## Gets the plain text docstring of a node non destructively.
##
## You need to call this before genRecComment, whose side effects are removal
## of comments from the tree. The proc will recursively scan and return all
## the concatenated ``##`` comments of the node.
result = ""
if n == nil: return
if n.comment != nil and startsWith(n.comment, "##"):
result = n.comment
if result.len < 1:
if n.kind notin {nkEmpty..nkNilLit}:
for i in countup(0, len(n)-1):
result = getPlainDocstring(n.sons[i])
if result.len > 0: return
proc findDocComment(n: PNode): PNode =
if n == nil: return nil
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
@@ -152,7 +177,7 @@ proc extractDocComment*(s: PSym, d: PDoc = nil): string =
if not d.isNil:
var dummyHasToc: bool
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLineNumber(n.info), toColumn(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}),
result)
else:
@@ -199,14 +224,111 @@ proc getRstName(n: PNode): PRstNode =
internalError(n.info, "getRstName()")
result = nil
proc newUniquePlainSymbol(d: PDoc, original: string): string =
## Returns a new unique plain symbol made up from the original.
##
## When a collision is found in the seenSymbols table, new numerical variants
## with underscore + number will be generated.
if not d.seenSymbols.hasKey(original):
result = original
d.seenSymbols[original] = ""
return
# Iterate over possible numeric variants of the original name.
var count = 2
while true:
result = original & "_" & $count
if not d.seenSymbols.hasKey(result):
d.seenSymbols[result] = ""
break
count += 1
proc complexName(k: TSymKind, n: PNode, baseName: string): string =
## Builds a complex unique href name for the node.
##
## Pass as ``baseName`` the plain symbol obtained from the nodeName. The
## format of the returned symbol will be ``baseName(.callable type)?,(param
## type)?(,param type)*``. The callable type part will be added only if the
## node is not a proc, as those are the common ones. The suffix will be a dot
## and a single letter representing the type of the callable. The parameter
## types will be added with a preceeding dash. Return types won't be added.
##
## If you modify the output of this proc, please update the anchor generation
## section of ``doc/docgen.txt``.
result = baseName
case k:
of skProc: result.add(defaultParamSeparator)
of skMacro: result.add(".m" & defaultParamSeparator)
of skMethod: result.add(".e" & defaultParamSeparator)
of skIterator: result.add(".i" & defaultParamSeparator)
of skTemplate: result.add(".t" & defaultParamSeparator)
of skConverter: result.add(".c" & defaultParamSeparator)
else: discard
if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
result.add(renderParamTypes(n[paramsPos]))
proc isCallable(n: PNode): bool =
## Returns true if `n` contains a callable node.
case n.kind
of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
nkConverterDef: result = true
else:
result = false
proc docstringSummary(rstText: string): string =
## Returns just the first line or a brief chunk of text from a rst string.
##
## Most docstrings will contain a one liner summary, so stripping at the
## first newline is usually fine. If after that the content is still too big,
## it is stripped at the first comma, colon or dot, usual english sentence
## separators.
##
## No guarantees are made on the size of the output, but it should be small.
## Also, we hope to not break the rst, but maybe we do. If there is any
## trimming done, an ellipsis unicode char is added.
const maxDocstringChars = 100
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
result = rstText.substr(2).strip
var pos = result.find('\L')
if pos > 0:
result.delete(pos, result.len - 1)
result.add("")
if pos < maxDocstringChars:
return
# Try to keep trimming at other natural boundaries.
pos = result.find({'.', ',', ':'})
let last = result.len - 1
if pos > 0 and pos < last:
result.delete(pos, last)
result.add("")
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return
var name = toRope(getName(d, nameNode))
let
name = getName(d, nameNode)
nameRope = name.toRope
plainDocstring = getPlainDocstring(n) # call here before genRecComment!
var result: PRope = nil
var literal = ""
var literal, plainName = ""
var kind = tkEof
var comm = genRecComment(d, n) # call this here for the side-effect!
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs})
while true:
getNextTok(r, kind, literal)
if kind == tkEof:
break
plainName.add(literal)
# Render the HTML hyperlink.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
while true:
getNextTok(r, kind, literal)
@@ -247,13 +369,47 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[toRope(esc(d.target, literal))])
inc(d.id)
let
plainNameRope = toRope(xmltree.escape(plainName.strip))
cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol)
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
itemIDRope = toRope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
var seeSrcRope: PRope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
["path", "line", "url"], [n.info.toFilename.toRope,
toRope($n.info.line), urlRope])])
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID"],
[name, result, comm, toRope(d.id)]))
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID"], [
toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
setIndexTerm(d[], $d.id, getName(d, nameNode))
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
[toRope(getName(d, nameNode, d.splitAfter)), result, comm,
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope]))
# Ironically for types the complexSymbol is *cleaner* than the plainName
# because it doesn't include object fields or documentation comments. So we
# use the plain one for callable elements, and the complex for the rest.
var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : "
if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip))
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary))
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
if not isVisible(nameNode): return
@@ -272,7 +428,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
result["code"] = %r.buf
proc checkForFalse(n: PNode): bool =
result = n.kind == nkIdent and IdentEq(n.ident, "false")
result = n.kind == nkIdent and identEq(n.ident, "false")
proc traceDeps(d: PDoc, n: PNode) =
const k = skModule
@@ -313,7 +469,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkImportStmt:
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: nil
else: discard
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
case n.kind
@@ -355,12 +511,12 @@ proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
# generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
discard generateJson(d, lastSon(n.sons[0]), jArray)
else: nil
else: discard
proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates"
"Iterators", "Iterators", "Converters", "Macros", "Templates"
]
if d.section[kind] == nil: return
var title = sectionNames[kind].toRope
@@ -408,7 +564,7 @@ proc genOutFile(d: PDoc): PRope =
proc generateIndex*(d: PDoc) =
if optGenIndex in gGlobalOptions:
writeIndexFile(d[], splitFile(options.outFile).dir /
splitFile(d.filename).name & indexExt)
splitFile(d.filename).name & IndexExt)
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d)
@@ -417,7 +573,7 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
else:
writeRope(content, getOutFile(filename, outExt), useWarning)
proc CommandDoc*() =
proc commandDoc*() =
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
@@ -426,7 +582,7 @@ proc CommandDoc*() =
writeOutput(d, gProjectFull, HtmlExt)
generateIndex(d)
proc CommandRstAux(filename, outExt: string) =
proc commandRstAux(filename, outExt: string) =
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, options.gConfigVars)
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
@@ -439,14 +595,14 @@ proc CommandRstAux(filename, outExt: string) =
writeOutput(d, filename, outExt)
generateIndex(d)
proc CommandRst2Html*() =
CommandRstAux(gProjectFull, HtmlExt)
proc commandRst2Html*() =
commandRstAux(gProjectFull, HtmlExt)
proc CommandRst2TeX*() =
proc commandRst2TeX*() =
splitter = "\\-"
CommandRstAux(gProjectFull, TexExt)
commandRstAux(gProjectFull, TexExt)
proc CommandJSON*() =
proc commandJSON*() =
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
@@ -460,7 +616,7 @@ proc CommandJSON*() =
echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc CommandBuildIndex*() =
proc commandBuildIndex*() =
var content = mergeIndexes(gProjectFull).toRope
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",

View File

@@ -27,7 +27,7 @@ proc close(p: PPassContext, n: PNode): PNode =
try:
generateIndex(g.doc)
except EIO:
nil
discard
proc processNode(c: PPassContext, n: PNode): PNode =
result = n
@@ -46,4 +46,4 @@ proc myOpen(module: PSym): PPassContext =
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
proc finishDoc2Pass*(project: string) =
nil
discard

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -9,7 +9,7 @@
## This file implements the FFI part of the evaluator for Nimrod code.
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
when defined(windows):
const libcDll = "msvcrt.dll"
@@ -20,7 +20,11 @@ type
TDllCache = tables.TTable[string, TLibHandle]
var
gDllCache = initTable[string, TLibHandle]()
gExeHandle = LoadLib()
when defined(windows):
var gExeHandle = loadLib(os.getAppFilename())
else:
var gExeHandle = loadLib()
proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = cache[dll]
@@ -28,15 +32,17 @@ proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
var libs: seq[string] = @[]
libCandidates(dll, libs)
for c in libs:
result = LoadLib(c)
result = loadLib(c)
if not result.isNil: break
if result.isNil:
GlobalError(info, "cannot load: " & dll)
globalError(info, "cannot load: " & dll)
cache[dll] = result
const
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
proc importcSymbol*(sym: PSym): PNode =
let name = ropeToStr(sym.loc.r)
@@ -47,10 +53,11 @@ proc importcSymbol*(sym: PSym): PNode =
of "stdin": result.intVal = cast[TAddress](system.stdin)
of "stdout": result.intVal = cast[TAddress](system.stdout)
of "stderr": result.intVal = cast[TAddress](system.stderr)
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
else:
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
globalError(sym.info, "dynlib needs to be a string lit for the REPL")
var theAddr: pointer
if lib.isNil and not gExehandle.isNil:
# first try this exe itself:
@@ -58,10 +65,12 @@ proc importcSymbol*(sym: PSym): PNode =
# then try libc:
if theAddr.isNil:
let dllhandle = gDllCache.getDll(libcDll, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
else:
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
theAddr = dllhandle.symAddr(name)
elif not lib.isNil:
let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll
else: lib.path.strVal, sym.info)
theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[TAddress](theAddr)
proc mapType(t: ast.PType): ptr libffi.TType =
@@ -78,7 +87,7 @@ proc mapType(t: ast.PType): ptr libffi.TType =
of tyFloat, tyFloat64: result = addr libffi.type_double
of tyFloat32: result = addr libffi.type_float
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
result = addr libffi.type_pointer
of tyDistinct:
result = mapType(t.sons[0])
@@ -93,7 +102,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
GlobalError(info, "cannot map calling convention to FFI")
globalError(info, "cannot map calling convention to FFI")
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
@@ -107,7 +116,7 @@ proc packSize(v: PNode, typ: PType): int =
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
else:
result = sizeof(pointer) + packSize(v.sons[0], typ.sons[0])
result = sizeof(pointer) + packSize(v.sons[0], typ.lastSon)
of tyDistinct, tyGenericInst:
result = packSize(v, typ.sons[0])
of tyArray, tyArrayConstr:
@@ -139,10 +148,10 @@ proc getField(n: PNode; position: int): PSym =
else: internalError(n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: nil
else: discard
proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind in {nkObjConstr, nkPar}
internalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets:
discard typ.getSize
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
@@ -155,7 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
let field = getField(typ.n, i)
pack(it, field.typ, res +! field.offset)
else:
GlobalError(x.info, "cannot pack unnamed tuple")
globalError(x.info, "cannot pack unnamed tuple")
const maxPackDepth = 20
var packRecCheck = 0
@@ -184,7 +193,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of 4: awr(int32, v.intVal.int32)
of 8: awr(int64, v.intVal.int64)
else:
GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
of tyFloat: awr(float, v.floatVal)
of tyFloat32: awr(float32, v.floatVal)
of tyFloat64: awr(float64, v.floatVal)
@@ -192,25 +201,25 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyPointer, tyProc, tyCString, tyString:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
elif v.kind in {nkStrLit..nkTripleStrLit}:
awr(cstring, cstring(v.strVal))
else:
GlobalError(v.info, "cannot map pointer/proc value to FFI")
globalError(v.info, "cannot map pointer/proc value to FFI")
of tyPtr, tyRef, tyVar:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
else:
if packRecCheck > maxPackDepth:
packRecCheck = 0
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
inc packRecCheck
pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
pack(v.sons[0], typ.lastSon, res +! sizeof(pointer))
dec packRecCheck
awr(pointer, res +! sizeof(pointer))
of tyArray, tyArrayConstr:
@@ -220,11 +229,11 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyObject, tyTuple:
packObject(v, typ, res)
of tyNil:
nil
discard
of tyDistinct, tyGenericInst:
pack(v, typ.sons[0], res)
else:
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
proc unpack(x: pointer, typ: PType, n: PNode): PNode
@@ -234,14 +243,14 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
for i in countup(0, sonsLen(n) - 1):
unpackObjectAdd(x, n.sons[i], result)
of nkRecCase:
GlobalError(result.info, "case objects cannot be unpacked")
globalError(result.info, "case objects cannot be unpacked")
of nkSym:
var pair = newNodeI(nkExprColonExpr, result.info, 2)
pair.sons[0] = n
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
result.add pair
else: nil
else: discard
proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
# compute the field's offsets:
@@ -253,14 +262,14 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
result = newNode(nkPar)
result.typ = typ
if typ.n.isNil:
InternalError("cannot unpack unnamed tuple")
internalError("cannot unpack unnamed tuple")
unpackObjectAdd(x, typ.n, result)
else:
result = n
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:
GlobalError(n.info, "cannot unpack unnamed tuple")
globalError(n.info, "cannot unpack unnamed tuple")
for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
@@ -279,7 +288,7 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
else:
result = n
if result.kind != nkBracket:
GlobalError(n.info, "cannot map value from FFI")
globalError(n.info, "cannot map value from FFI")
let baseSize = typ.sons[1].getSize
for i in 0 .. < result.len:
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
@@ -303,7 +312,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
#echo "expected ", k, " but got ", result.kind
#debug result
return newNodeI(nkExceptBranch, n.info)
#GlobalError(n.info, "cannot map value from FFI")
#globalError(n.info, "cannot map value from FFI")
result.field = v
template setNil() =
@@ -328,19 +337,19 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
of tyInt16: awi(nkInt16Lit, rd(int16, x))
of tyInt32: awi(nkInt32Lit, rd(int32, x))
of tyInt64: awi(nkInt64Lit, rd(int64, x))
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
of tyEnum:
case typ.getSize
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
of 4: awi(nkIntLit, rd(int32, x).biggestInt)
of 8: awi(nkIntLit, rd(int64, x).biggestInt)
of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
@@ -362,10 +371,10 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
awi(nkPtrLit, cast[TAddress](p))
elif n != nil and n.len == 1:
internalAssert n.kind == nkRefTy
n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
result = n
else:
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(x, typ, n)
of tyArray, tyArrayConstr:
@@ -382,7 +391,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
result = unpack(x, typ.sons[0], n)
else:
# XXX what to do with 'array' here?
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(x: PNode, destTyp: PType): PNode =
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer,
@@ -405,7 +414,7 @@ proc fficast*(x: PNode, destTyp: PType): PNode =
dealloc a
proc callForeignFunction*(call: PNode): PNode =
InternalAssert call.sons[0].kind == nkPtrLit
internalAssert call.sons[0].kind == nkPtrLit
var cif: TCif
var sig: TParamList
@@ -413,12 +422,12 @@ proc callForeignFunction*(call: PNode): PNode =
for i in 1..call.len-1:
sig[i-1] = mapType(call.sons[i].typ)
if sig[i-1].isNil:
GlobalError(call.info, "cannot map FFI type")
globalError(call.info, "cannot map FFI type")
let typ = call.sons[0].typ
if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
mapType(typ.sons[0]), sig) != OK:
GlobalError(call.info, "error in FFI call")
globalError(call.info, "error in FFI call")
var args: TArgList
let fn = cast[pointer](call.sons[0].intVal)
@@ -441,3 +450,46 @@ proc callForeignFunction*(call: PNode): PNode =
for i in 1 .. call.len-1:
call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
dealloc args[i-1]
proc callForeignFunction*(fn: PNode, fntyp: PType,
args: var TNodeSeq, start, len: int,
info: TLineInfo): PNode =
internalAssert fn.kind == nkPtrLit
var cif: TCif
var sig: TParamList
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
internalAssert i+1 < fntyp.len
aTyp = fntyp.sons[i+1]
args[i+start].typ = aTyp
sig[i] = mapType(aTyp)
if sig[i].isNil: globalError(info, "cannot map FFI type")
if prep_cif(cif, mapCallConv(fntyp.callConv, info), cuint(len),
mapType(fntyp.sons[0]), sig) != OK:
globalError(info, "error in FFI call")
var cargs: TArgList
let fn = cast[pointer](fn.intVal)
for i in 0 .. len-1:
let t = args[i+start].typ
cargs[i] = alloc0(packSize(args[i+start], t))
pack(args[i+start], t, cargs[i])
let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
else: alloc(fntyp.sons[0].getSize.int)
libffi.call(cif, fn, retVal, cargs)
if retVal.isNil:
result = emptyNode
else:
result = unpack(retVal, fntyp.sons[0], nil)
result.info = info
if retVal != nil: dealloc retVal
for i in 0 .. len-1:
let t = args[i+start].typ
args[i+start] = unpack(cargs[i], t, args[i+start])
dealloc cargs[i]

View File

@@ -91,6 +91,7 @@ proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
if defined(debug) and gVerbosity >= 3: writeStackTrace()
result = newNodeI(nkExceptBranch, info)
# creating a nkExceptBranch without sons
# means that it could not be evaluated
@@ -263,8 +264,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128:
result = newNodeIt(nkFloatLit, info, t)
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc:
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyStatic, tyProc:
result = newNodeIT(nkNilLit, info, t)
of tyObject:
result = newNodeIT(nkPar, info, t)
@@ -358,7 +359,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
result = efLValue in flags or n.typ == nil or
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
n.typ.kind in {tyExpr, tyStatic, tyStmt, tyTypeDesc}
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
# We need to return a node to the actual value,
@@ -905,17 +906,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
result = parseString(code.getStrValue, code.info.toFilename,
code.info.line.int)
#result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
InternalAssert operand.kind == nkSym
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
let typ = operand.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = trait.info
of "arity":
of "arity":
result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context)
result.info = trait.info
@@ -1329,7 +1328,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
case n.kind
of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit:
of nkType..nkNilLit, nkTypeOfExpr:
# nkStrLit is VERY common in the traces, so we should avoid
# the 'copyNode' here.
result = n #.copyNode

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -16,9 +16,14 @@ import
type
TemplCtx {.pure, final.} = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
if ctx.instLines: result.info = b.info
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
case templ.kind
of nkSym:
@@ -31,49 +36,23 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
else:
result.add copyTree(x)
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
internalAssert sfGenSym in s.flags
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result.add newSymNode(x, templ.info)
idTablePut(c.mapping, s, x)
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
else:
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
else:
var res = copyNode(templ)
var res = copyNode(c, templ, actual)
for i in countup(0, sonsLen(templ) - 1):
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
when false:
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx): PNode =
case templ.kind
of nkSym:
var s = templ.sym
if s.owner.id == c.owner.id:
if s.kind == skParam:
result = copyTree(actual.sons[s.position])
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result = newSymNode(x, templ.info)
else:
result = copyNode(templ)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result = copyNode(templ)
else:
result = copyNode(templ)
newSons(result, sonsLen(templ))
for i in countup(0, sonsLen(templ) - 1):
result.sons[i] = evalTemplateAux(templ.sons[i], actual, c)
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
@@ -83,13 +62,13 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
a = sonsLen(n)
else: a = 0
var f = s.typ.sonsLen
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
if a > f: globalError(n.info, errWrongNumberOfArguments)
result = newNodeI(nkArgList, n.info)
for i in countup(1, f - 1):
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
localError(n.info, errWrongNumberOfArguments)
addSon(result, arg)
var evalTemplateCounter* = 0
@@ -98,7 +77,7 @@ var evalTemplateCounter* = 0
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node:
@@ -114,11 +93,13 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0]
else:
GlobalError(result.info, errIllFormedAstX,
globalError(result.info, errIllFormedAstX,
renderTree(result, {renderNoComments}))
else:
result = copyNode(body)
#evalTemplateAux(body, args, ctx, result)
ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
nkBlockStmt, nkBlockExpr}
if ctx.instLines: result.info = n.info
for i in countup(0, safeLen(body) - 1):
evalTemplateAux(body.sons[i], args, ctx, result)

View File

@@ -16,7 +16,7 @@ import
type
TSystemCC* = enum
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccGpp
ccTcc, ccPcc, ccUcc, ccIcl
TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
hasComputedGoto, # CC has computed goto (GNU C extension)
@@ -33,11 +33,12 @@ type
optSpeed: string, # the options for optimization for speed
optSize: string, # the options for optimization for size
compilerExe: string, # the compiler's executable
cppCompiler: string, # name of the C++ compiler's executable (if supported)
compileTmpl: string, # the compile command template
buildGui: string, # command to build a GUI application
buildDll: string, # command to build a shared library
buildLib: string, # command to build a static library
linkerExe: string, # the linker's executable
linkerExe: string, # the linker's executable (if not matching compiler's)
linkTmpl: string, # command to link files to produce an exe
includeCmd: string, # command to add an include dir
linkDirCmd: string, # command to add a lib dir
@@ -46,6 +47,8 @@ type
pic: string, # command for position independent code
# used on some platforms
asmStmtFrmt: string, # format of ASM statement
structStmtFmt: string, # Format for struct statement
packedPragma: string, # Attribute/pragma to make struct packed (1-byte aligned)
props: TInfoCCProps] # properties of the C compiler
@@ -63,11 +66,12 @@ compiler gcc:
optSpeed: " -O3 -ffast-math ",
optSize: " -Os -ffast-math ",
compilerExe: "gcc",
cppCompiler: "g++",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: " -mwindows",
buildDll: " -shared",
buildLib: "ar rcs $libfile $objfiles",
linkerExe: "gcc",
linkerExe: "",
linkTmpl: "$buildgui $builddll -o $exefile $objfiles $options",
includeCmd: " -I",
linkDirCmd: " -L",
@@ -75,34 +79,25 @@ compiler gcc:
debug: "",
pic: "-fPIC",
asmStmtFrmt: "asm($1);$n",
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
packedPragma: "__attribute__((__packed__))",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasNakedAttribute})
compiler gpp:
result = gcc()
result.name = "gpp"
result.compilerExe = "g++"
result.linkerExe = "g++"
result.buildDll = " -mdll"
# XXX: Hmm, I'm keeping this from the previos version,
# but my gcc doesn't even have such an option (is this mingw?)
compiler llvmGcc:
result = gcc()
result.name = "llvm_gcc"
result.compilerExe = "llvm-gcc"
result.cppCompiler = "llvm-g++"
result.buildLib = "llvm-ar rcs $libfile $objfiles"
result.linkerExe = "llvm-gcc"
compiler clang:
result = llvmGcc()
result.name = "clang"
result.compilerExe = "clang"
result.linkerExe = "clang"
result.cppCompiler = "clang++"
compiler vcc:
result = (
@@ -111,6 +106,7 @@ compiler vcc:
optSpeed: " /Ogityb2 /G7 /arch:SSE2 ",
optSize: " /O1 /G7 ",
compilerExe: "cl",
cppCompiler: "cl",
compileTmpl: "/c $options $include /Fo$objfile $file",
buildGui: " /link /SUBSYSTEM:WINDOWS ",
buildDll: " /LD",
@@ -123,6 +119,8 @@ compiler vcc:
debug: " /GZ /Zi ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$3$n$1 $2",
packedPragma: "#pragma pack(1)",
props: {hasCpp, hasAssume, hasNakedDeclspec})
compiler icl:
@@ -131,7 +129,7 @@ compiler icl:
result = vcc()
else:
result = gcc()
result.name = "icl"
result.compilerExe = "icl"
result.linkerExe = "icl"
@@ -143,6 +141,7 @@ compiler lcc:
optSpeed: " -O -p6 ",
optSize: " -O -p6 ",
compilerExe: "lcc",
cppCompiler: "",
compileTmpl: "$options $include -Fo$objfile $file",
buildGui: " -subsystem windows",
buildDll: " -dll",
@@ -155,6 +154,8 @@ compiler lcc:
debug: " -g5 ",
pic: "",
asmStmtFrmt: "_asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
compiler bcc:
@@ -164,6 +165,7 @@ compiler bcc:
optSpeed: " -O2 -6 ",
optSize: " -O1 -6 ",
compilerExe: "bcc32",
cppCompiler: "",
compileTmpl: "-c $options $include -o$objfile $file",
buildGui: " -tW",
buildDll: " -tWD",
@@ -176,6 +178,8 @@ compiler bcc:
debug: "",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
compiler dmc:
@@ -185,6 +189,7 @@ compiler dmc:
optSpeed: " -ff -o -6 ",
optSize: " -ff -o -6 ",
compilerExe: "dmc",
cppCompiler: "",
compileTmpl: "-c $options $include -o$objfile $file",
buildGui: " -L/exet:nt/su:windows",
buildDll: " -WD",
@@ -197,6 +202,8 @@ compiler dmc:
debug: " -g ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$3$n$1 $2",
packedPragma: "#pragma pack(1)",
props: {hasCpp})
compiler wcc:
@@ -206,6 +213,7 @@ compiler wcc:
optSpeed: " -ox -on -6 -d0 -fp6 -zW ",
optSize: "",
compilerExe: "wcl386",
cppCompiler: "",
compileTmpl: "-c $options $include -fo=$objfile $file",
buildGui: " -bw",
buildDll: " -bd",
@@ -218,6 +226,8 @@ compiler wcc:
debug: " -d2 ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
compiler tcc:
@@ -227,6 +237,7 @@ compiler tcc:
optSpeed: "",
optSize: "",
compilerExe: "tcc",
cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "UNAVAILABLE!",
buildDll: " -shared",
@@ -239,6 +250,8 @@ compiler tcc:
debug: " -g ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasSwitchRange, hasComputedGoto})
compiler pcc:
@@ -249,6 +262,7 @@ compiler pcc:
optSpeed: " -Ox ",
optSize: " -Os ",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $options $include -Fo$objfile $file",
buildGui: " -SUBSYSTEM:WINDOWS",
buildDll: " -DLL",
@@ -261,6 +275,8 @@ compiler pcc:
debug: " -Zi ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
compiler ucc:
@@ -270,6 +286,7 @@ compiler ucc:
optSpeed: " -O3 ",
optSize: " -O1 ",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "",
buildDll: " -shared ",
@@ -282,6 +299,8 @@ compiler ucc:
debug: "",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
const
@@ -297,8 +316,7 @@ const
tcc(),
pcc(),
ucc(),
icl(),
gpp()]
icl()]
const
hExt* = ".h"
@@ -324,7 +342,7 @@ var
compileOptions: string = ""
ccompilerpath: string = ""
proc NameToCC*(name: string): TSystemCC =
proc nameToCC*(name: string): TSystemCC =
for i in countup(succ(ccNone), high(TSystemCC)):
if cmpIgnoreStyle(name, CC[i].name) == 0:
return i
@@ -335,8 +353,8 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
# for niminst support
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
optCompileOnly notin gGlobalOptions:
let fullCCname = platform.cpu[targetCPU].name & '.' &
platform.os[targetOS].name & '.' &
let fullCCname = platform.CPU[targetCPU].name & '.' &
platform.OS[targetOS].name & '.' &
CC[c].name & suffix
result = getConfigVar(fullCCname)
if result.len == 0:
@@ -346,13 +364,13 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
result = getConfigVar(CC[c].name & suffix)
proc setCC*(ccname: string) =
ccompiler = nameToCC(ccname)
if ccompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(ccompiler, ".options.always")
linkOptions = getConfigVar(ccompiler, ".options.linker")
ccompilerpath = getConfigVar(ccompiler, ".path")
cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always")
linkOptions = getConfigVar(cCompiler, ".options.linker")
ccompilerpath = getConfigVar(cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[ccompiler].name)
defineSymbol(CC[cCompiler].name)
proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
@@ -368,20 +386,20 @@ proc addCompileOption*(option: string) =
proc initVars*() =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[ccompiler].name)
defineSymbol(CC[cCompiler].name)
if gCmd == cmdCompileToCpp: cExt = ".cpp"
elif gCmd == cmdCompileToOC: cExt = ".m"
addCompileOption(getConfigVar(ccompiler, ".options.always"))
addLinkOption(getConfigVar(ccompiler, ".options.linker"))
if len(ccompilerPath) == 0:
ccompilerpath = getConfigVar(ccompiler, ".path")
addCompileOption(getConfigVar(cCompiler, ".options.always"))
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path")
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(cfile, createSubDir)
proc toObjFile*(filenameWithoutExt: string): string =
# Object file for compilation
result = changeFileExt(filenameWithoutExt, cc[ccompiler].objExt)
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
proc addFileToCompile*(filename: string) =
appendStr(toCompile, filename)
@@ -400,28 +418,28 @@ proc addFileToLink*(filename: string) =
# BUGFIX: was ``appendStr``
proc execExternalProgram*(cmd: string) =
if optListCmd in gGlobalOptions or gVerbosity > 0: MsgWriteln(cmd)
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
proc generateScript(projectFile: string, script: PRope) =
let (dir, name, ext) = splitFile(projectFile)
WriteRope(script, dir / addFileExt("compile_" & name,
platform.os[targetOS].scriptExt))
writeRope(script, dir / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt))
proc getOptSpeed(c: TSystemCC): string =
result = getConfigVar(c, ".options.speed")
if result == "":
result = cc[c].optSpeed # use default settings from this file
result = CC[c].optSpeed # use default settings from this file
proc getDebug(c: TSystemCC): string =
result = getConfigVar(c, ".options.debug")
if result == "":
result = cc[c].debug # use default settings from this file
result = CC[c].debug # use default settings from this file
proc getOptSize(c: TSystemCC): string =
result = getConfigVar(c, ".options.size")
if result == "":
result = cc[c].optSize # use default settings from this file
result = CC[c].optSize # use default settings from this file
proc noAbsolutePaths: bool {.inline.} =
# We used to check current OS != specified OS, but this makes no sense
@@ -436,78 +454,88 @@ const
var fileCounter: int
proc add(s: var string, many: openarray[string]) =
proc add(s: var string, many: openArray[string]) =
s.add many.join
proc CFileSpecificOptions(cfilename: string): string =
proc cFileSpecificOptions(cfilename: string): string =
result = compileOptions
var trunk = splitFile(cfilename).name
if optCDebug in gGlobalOptions:
var key = trunk & ".debug"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getDebug(ccompiler))
else: addOpt(result, getDebug(cCompiler))
if optOptimizeSpeed in gOptions:
var key = trunk & ".speed"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSpeed(ccompiler))
else: addOpt(result, getOptSpeed(cCompiler))
elif optOptimizeSize in gOptions:
var key = trunk & ".size"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSize(ccompiler))
else: addOpt(result, getOptSize(cCompiler))
var key = trunk & ".always"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
proc getCompileOptions: string =
result = CFileSpecificOptions("__dummy__")
result = cFileSpecificOptions("__dummy__")
proc getLinkOptions: string =
result = linkOptions
for linkedLib in items(cLinkedLibs):
result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteShell)
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
for libDir in items(cLibs):
result.add([cc[ccompiler].linkDirCmd, libDir.quoteShell])
result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell])
proc needsExeExt(): bool {.inline.} =
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
(platform.hostOS == osWindows)
proc getCompilerExe(compiler: TSystemCC): string =
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
else: CC[compiler].compilerExe
if result.len == 0:
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
proc getLinkerExe(compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
else: compiler.getCompilerExe
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
var c = ccompiler
var options = CFileSpecificOptions(cfilename)
var c = cCompiler
var options = cFileSpecificOptions(cfilename)
var exe = getConfigVar(c, ".exe")
if exe.len == 0: exe = cc[c].compilerExe
if exe.len == 0: exe = c.getCompilerExe
if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and
ospNeedsPIC in platform.OS[targetOS].props:
add(options, ' ' & cc[c].pic)
add(options, ' ' & CC[c].pic)
var includeCmd, compilePattern: string
if not noAbsolutePaths():
# compute include paths:
includeCmd = cc[c].includeCmd & quoteShell(libpath)
includeCmd = CC[c].includeCmd & quoteShell(libpath)
for includeDir in items(cIncludes):
includeCmd.add([cc[c].includeCmd, includeDir.quoteShell])
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
compilePattern = JoinPath(ccompilerpath, exe)
compilePattern = joinPath(ccompilerpath, exe)
else:
includeCmd = ""
compilePattern = cc[c].compilerExe
compilePattern = c.getCompilerExe
var cfile = if noAbsolutePaths(): extractFileName(cfilename)
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
else: cfilename
var objfile = if not isExternal or noAbsolutePaths():
toObjFile(cfile)
else:
completeCFilePath(toObjFile(cfile))
cfile = quoteShell(AddFileExt(cfile, cExt))
cfile = quoteShell(addFileExt(cfile, cExt))
objfile = quoteShell(objfile)
result = quoteShell(compilePattern % [
"file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
add(result, ' ')
addf(result, cc[c].compileTmpl, [
addf(result, CC[c].compileTmpl, [
"file", cfile, "objfile", objfile,
"options", options, "include", includeCmd,
"nimrod", quoteShell(getPrefixDir()),
@@ -517,7 +545,7 @@ proc footprint(filename: string): TCrc32 =
result = crcFromFile(filename) ><
platform.OS[targetOS].name ><
platform.CPU[targetCPU].name ><
extccomp.CC[extccomp.ccompiler].name ><
extccomp.CC[extccomp.cCompiler].name ><
getCompileCFileCmd(filename, true)
proc externalFileChanged(filename: string): bool =
@@ -541,7 +569,7 @@ 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) =
var it = PStrEntry(list.head)
while it != nil:
@@ -554,18 +582,18 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
app(script, tnl)
it = PStrEntry(it.next)
proc CallCCompiler*(projectfile: string) =
proc callCCompiler*(projectfile: string) =
var
linkCmd, buildgui, builddll: string
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
fileCounter = 0
var c = ccompiler
var c = cCompiler
var script: PRope = nil
var cmds: TStringSeq = @[]
CompileCFile(toCompile, script, cmds, false)
CompileCFile(externalToCompile, script, cmds, true)
compileCFile(toCompile, script, cmds, false)
compileCFile(externalToCompile, script, cmds, true)
if optCompileOnly notin gGlobalOptions:
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
@@ -591,40 +619,40 @@ proc CallCCompiler*(projectfile: string) =
let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
add(objfiles, ' ')
add(objfiles, quoteShell(
addFileExt(objFile, cc[ccompiler].objExt)))
addFileExt(objFile, CC[cCompiler].objExt)))
it = PStrEntry(it.next)
if optGenStaticLib in gGlobalOptions:
linkcmd = cc[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
"objfiles", objfiles]
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
else:
var linkerExe = getConfigVar(c, ".linkerexe")
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
else: linkCmd = quoteShell(JoinPath(ccompilerpath, linkerExe))
if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
else: buildGui = ""
else: linkCmd = quoteShell(joinPath(ccompilerpath, linkerExe))
if optGenGuiApp in gGlobalOptions: buildgui = CC[c].buildGui
else: buildgui = ""
var exefile: string
if optGenDynLib in gGlobalOptions:
exefile = platform.os[targetOS].dllFrmt % splitFile(projectFile).name
buildDll = cc[c].buildDll
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
builddll = CC[c].buildDll
else:
exefile = splitFile(projectFile).name & platform.os[targetOS].exeExt
buildDll = ""
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
builddll = ""
if options.outFile.len > 0:
exefile = options.outFile.expandTilde
if not noAbsolutePaths():
if not exeFile.isAbsolute():
exefile = joinPath(splitFile(projectFile).dir, exefile)
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions()
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
linkCmd.add ' '
addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile,
"nimrod", quoteShell(getPrefixDir()),
@@ -635,12 +663,12 @@ proc CallCCompiler*(projectfile: string) =
if optGenScript in gGlobalOptions:
app(script, linkCmd)
app(script, tnl)
generateScript(projectFile, script)
generateScript(projectfile, script)
proc genMappingFiles(list: TLinkedList): PRope =
var it = PStrEntry(list.head)
while it != nil:
appf(result, "--file:r\"$1\"$N", [toRope(AddFileExt(it.data, cExt))])
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
it = PStrEntry(it.next)
proc writeMapping*(gSymbolMapping: PRope) =
@@ -658,5 +686,5 @@ proc writeMapping*(gSymbolMapping: PRope) =
app(code, strutils.escape(libpath))
appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
WriteRope(code, joinPath(gProjectPath, "mapping.txt"))
writeRope(code, joinPath(gProjectPath, "mapping.txt"))

View File

@@ -27,7 +27,7 @@ type
indent, emitPar: int
x: string # the current input line
outp: PLLStream # the ouput will be parsed by pnimsyn
subsChar, NimDirective: Char
subsChar, nimDirective: char
emit, conc, toStr: string
curly, bracket, par: int
pendingExprLine: bool
@@ -37,11 +37,11 @@ const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
proc newLine(p: var TTmplParser) =
LLStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
p.emitPar = 0
if p.info.line > int16(1): LLStreamWrite(p.outp, "\n")
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
if p.pendingExprLine:
LLStreamWrite(p.outp, repeatChar(2))
llStreamWrite(p.outp, repeatChar(2))
p.pendingExprLine = false
proc scanPar(p: var TTmplParser, d: int) =
@@ -55,7 +55,7 @@ proc scanPar(p: var TTmplParser, d: int) =
of ']': dec(p.bracket)
of '{': inc(p.curly)
of '}': dec(p.curly)
else: nil
else: discard
inc(i)
proc withInExpr(p: TTmplParser): bool {.inline.} =
@@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) =
keyw: string
j = 0
while p.x[j] == ' ': inc(j)
if (p.x[0] == p.NimDirective) and (p.x[0 + 1] == '!'):
if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'):
newLine(p)
elif (p.x[j] == p.NimDirective):
elif (p.x[j] == p.nimDirective):
newLine(p)
inc(j)
while p.x[j] == ' ': inc(j)
@@ -87,26 +87,26 @@ proc parseLine(p: var TTmplParser) =
dec(p.indent, 2)
else:
p.info.col = int16(j)
LocalError(p.info, errXNotAllowedHere, "end")
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, "#end")
localError(p.info, errXNotAllowedHere, "end")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, "#end")
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
wConverter, wMacro, wTemplate, wMethod:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
inc(p.indent, 2)
of wElif, wOf, wElse, wExcept, wFinally:
LLStreamWrite(p.outp, repeatChar(p.indent - 2))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent - 2))
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))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
if not p.x.contains({':', '='}):
# no inline element --> treat as block:
inc(p.indent, 2)
else:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
p.state = psDirective
else:
# data line
@@ -118,15 +118,15 @@ proc parseLine(p: var TTmplParser) =
case p.state
of psTempl:
# next line of string literal:
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, "\n")
LLStreamWrite(p.outp, repeatChar(p.indent + 2))
LLStreamWrite(p.outp, "\"")
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, "\n")
llStreamWrite(p.outp, repeatChar(p.indent + 2))
llStreamWrite(p.outp, "\"")
of psDirective:
newLine(p)
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, p.emit)
LLStreamWrite(p.outp, "(\"")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, p.emit)
llStreamWrite(p.outp, "(\"")
inc(p.emitPar)
p.state = psTempl
while true:
@@ -134,17 +134,17 @@ proc parseLine(p: var TTmplParser) =
of '\0':
break
of '\x01'..'\x1F', '\x80'..'\xFF':
LLStreamWrite(p.outp, "\\x")
LLStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
llStreamWrite(p.outp, "\\x")
llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
inc(j)
of '\\':
LLStreamWrite(p.outp, "\\\\")
llStreamWrite(p.outp, "\\\\")
inc(j)
of '\'':
LLStreamWrite(p.outp, "\\\'")
llStreamWrite(p.outp, "\\\'")
inc(j)
of '\"':
LLStreamWrite(p.outp, "\\\"")
llStreamWrite(p.outp, "\\\"")
inc(j)
else:
if p.x[j] == p.subsChar:
@@ -153,59 +153,59 @@ proc parseLine(p: var TTmplParser) =
case p.x[j]
of '{':
p.info.col = int16(j)
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
inc(j)
curly = 0
while true:
case p.x[j]
of '\0':
LocalError(p.info, errXExpected, "}")
localError(p.info, errXExpected, "}")
break
of '{':
inc(j)
inc(curly)
LLStreamWrite(p.outp, '{')
llStreamWrite(p.outp, '{')
of '}':
inc(j)
if curly == 0: break
if curly > 0: dec(curly)
LLStreamWrite(p.outp, '}')
llStreamWrite(p.outp, '}')
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
while p.x[j] in PatternChars:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
else:
if p.x[j] == p.subsChar:
LLStreamWrite(p.outp, p.subsChar)
llStreamWrite(p.outp, p.subsChar)
inc(j)
else:
p.info.col = int16(j)
LocalError(p.info, errInvalidExpression, "$")
localError(p.info, errInvalidExpression, "$")
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, "\\n\"")
llStreamWrite(p.outp, "\\n\"")
proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var p: TTmplParser
p.info = newLineInfo(filename, 0, 0)
p.outp = LLStreamOpen("")
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(call, "subschar", 1, '$')
p.nimDirective = charArg(call, "metachar", 2, '#')
@@ -213,9 +213,9 @@ proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
p.conc = strArg(call, "conc", 4, " & ")
p.toStr = strArg(call, "tostring", 5, "$")
p.x = newStringOfCap(120)
while LLStreamReadLine(p.inp, p.x):
while llStreamReadLine(p.inp, p.x):
p.info.line = p.info.line + int16(1)
parseLine(p)
newLine(p)
result = p.outp
LLStreamClose(p.inp)
llStreamClose(p.inp)

View File

@@ -16,13 +16,13 @@ import
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream
# helpers to retrieve arguments:
proc charArg*(n: PNode, name: string, pos: int, default: Char): Char
proc charArg*(n: PNode, name: string, pos: int, default: char): char
proc strArg*(n: PNode, name: string, pos: int, default: string): string
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
# implementation
proc invalidPragma(n: PNode) =
LocalError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
proc getArg(n: PNode, name: string, pos: int): PNode =
result = nil
@@ -30,12 +30,12 @@ proc getArg(n: PNode, name: string, pos: int): PNode =
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
if IdentEq(n.sons[i].sons[0].ident, name):
if identEq(n.sons[i].sons[0].ident, name):
return n.sons[i].sons[1]
elif i == pos:
return n.sons[i]
proc charArg(n: PNode, name: string, pos: int, default: Char): Char =
proc charArg(n: PNode, name: string, pos: int, default: char): char =
var x = getArg(n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
@@ -50,30 +50,30 @@ proc strArg(n: PNode, name: string, pos: int, default: string): string =
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(n, name, pos)
if x == nil: result = default
elif (x.kind == nkIdent) and IdentEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and IdentEq(x.ident, "false"): result = false
elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
else: invalidPragma(n)
proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(call, "startswith", 1, "")
var leading = boolArg(call, "leading", 2, true)
var trailing = boolArg(call, "trailing", 3, true)
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
while llStreamReadLine(stdin, line):
var stripped = strip(line, leading, trailing)
if (len(pattern) == 0) or startsWith(stripped, pattern):
LLStreamWriteln(result, stripped)
llStreamWriteln(result, stripped)
else:
LLStreamWriteln(result, line)
LLStreamClose(stdin)
llStreamWriteln(result, line)
llStreamClose(stdin)
proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(call, "sub", 1, "")
if len(sub) == 0: invalidPragma(call)
var by = strArg(call, "by", 2, "")
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
LLStreamWriteln(result, replace(line, sub, by))
LLStreamClose(stdin)
while llStreamReadLine(stdin, line):
llStreamWriteln(result, replace(line, sub, by))
llStreamClose(stdin)

View File

@@ -9,7 +9,7 @@
## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents
const
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@@ -69,9 +69,23 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
proc swapArgs(fact: PNode, newOp: string, m: TMagic): PNode =
proc getMagicOp(name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m
let
opLe = getMagicOp("<=", mLeI)
opLt = getMagicOp("<", mLtI)
opAnd = getMagicOp("and", mAnd)
opOr = getMagicOp("or", mOr)
opNot = getMagicOp("not", mNot)
opIsNil = getMagicOp("isnil", mIsNil)
opContains = getMagicOp("contains", mInSet)
opEq = getMagicOp("==", mEqI)
proc swapArgs(fact: PNode, newOp: PSym): PNode =
result = newNodeI(nkCall, fact.info, 3)
result.sons[0] = newSymNode(getSysMagic(newOp, m))
result.sons[0] = newSymNode(newOp)
result.sons[1] = fact.sons[2]
result.sons[2] = fact.sons[1]
@@ -82,9 +96,9 @@ proc neg(n: PNode): PNode =
result = n.sons[1]
of someLt:
# not (a < b) == a >= b == b <= a
result = swapArgs(n, "<=", mLeI)
result = swapArgs(n, opLe)
of someLe:
result = swapArgs(n, "<", mLtI)
result = swapArgs(n, opLt)
of mInSet:
if n.sons[1].kind != nkCurly: return nil
let t = n.sons[2].typ.skipTypes(abstractInst)
@@ -110,7 +124,7 @@ proc neg(n: PNode): PNode =
b = n.sons[2].neg
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(getSysMagic("and", mAnd))
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
@@ -120,12 +134,12 @@ proc neg(n: PNode): PNode =
else:
# leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2)
result.sons[0] = newSymNode(getSysMagic("not", mNot))
result.sons[0] = newSymNode(opNot)
result.sons[1] = n
proc buildIsNil(arg: PNode): PNode =
result = newNodeI(nkCall, arg.info, 2)
result.sons[0] = newSymNode(getSysMagic("isNil", mIsNil))
result.sons[0] = newSymNode(opIsNil)
result.sons[1] = arg
proc usefulFact(n: PNode): PNode =
@@ -154,7 +168,7 @@ proc usefulFact(n: PNode): PNode =
b = usefulFact(n.sons[2])
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(getSysMagic("and", mAnd))
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
@@ -177,7 +191,7 @@ proc usefulFact(n: PNode): PNode =
b = usefulFact(n.sons[2]).neg
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(getSysMagic("and", mAnd))
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
result = result.neg
@@ -251,19 +265,15 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:
result = not SameValue(a, b)
result = not sameValue(a, b)
proc pred(n: PNode): PNode =
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(biggestInt):
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
result = copyNode(n)
dec result.intVal
else:
result = n
type
TImplication* = enum
impUnknown, impNo, impYes
proc impliesEq(fact, eq: PNode): TImplication =
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
@@ -366,7 +376,7 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
else: discard
proc impliesGe(fact, x, c: PNode): TImplication =
InternalAssert isLocation(x)
internalAssert isLocation(x)
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], x):
@@ -439,7 +449,7 @@ proc impliesLe(fact, x, c: PNode): TImplication =
if leValue(c, fact.sons[1].pred): result = impNo
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
else: nil
else: discard
proc impliesLt(fact, x, c: PNode): TImplication =
# x < 3 same as x <= 2:
@@ -484,7 +494,7 @@ proc factImplies(fact, prop: PNode): TImplication =
if a == b: return ~a
return impUnknown
else:
InternalError(fact.info, "invalid fact")
internalError(fact.info, "invalid fact")
of mAnd:
result = factImplies(fact.sons[1], prop)
if result != impUnknown: return result
@@ -520,7 +530,7 @@ proc buildOf(it, loc: PNode): PNode =
s.typ = settype(loc)
for i in 0..it.len-2: s.sons[i] = it.sons[i]
result = newNodeI(nkCall, it.info, 3)
result.sons[0] = newSymNode(getSysMagic("contains", mInSet))
result.sons[0] = newSymNode(opContains)
result.sons[1] = s
result.sons[2] = loc
@@ -532,20 +542,20 @@ proc buildElse(n: PNode): PNode =
for j in 0..branch.len-2:
s.add(branch.sons[j])
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(getSysMagic("contains", mInSet))
result.sons[0] = newSymNode(opContains)
result.sons[1] = s
result.sons[2] = n.sons[0]
proc addDiscriminantFact*(m: var TModel, n: PNode) =
var fact = newNodeI(nkCall, n.info, 3)
fact.sons[0] = newSymNode(getSysMagic("==", mEqI))
fact.sons[0] = newSymNode(opEq)
fact.sons[1] = n.sons[0]
fact.sons[2] = n.sons[1]
m.add fact
proc addAsgnFact*(m: var TModel, key, value: PNode) =
var fact = newNodeI(nkCall, key.info, 3)
fact.sons[0] = newSymNode(getSysMagic("==", mEqI))
fact.sons[0] = newSymNode(opEq)
fact.sons[1] = key
fact.sons[2] = value
m.add fact
@@ -575,4 +585,4 @@ proc checkFieldAccess*(m: TModel, n: PNode) =
for i in 1..n.len-1:
let check = buildProperFieldCheck(n.sons[0], n.sons[i])
if m.doesImply(check) != impYes:
Message(n.info, warnProveField, renderTree(n.sons[0])); break
message(n.info, warnProveField, renderTree(n.sons[0])); break

View File

@@ -12,7 +12,7 @@
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
@@ -28,7 +28,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
else:
result = semDirectOp(c, n, {})
if optHints in gOptions and hintPattern in gNotes:
Message(orig.info, hintPattern, rule & " --> '" &
message(orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'")
proc applyPatterns(c: PContext, n: PNode): PNode =
@@ -45,7 +45,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
# better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
# deactivate this pattern:
c.patterns[i] = nil
if x.kind == nkStmtList:
@@ -68,7 +68,8 @@ proc hlo(c: PContext, n: PNode): PNode =
result = n
else:
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
n.sons[0].kind == nkSym and sfGlobal in n.sons[0].sym.flags:
n.sons[0].kind == nkSym and
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)
@@ -81,7 +82,7 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
# perform type checking, so that the replacement still fits:
if isEmptyType(n.typ) and isEmptyType(result.typ):
nil
discard
else:
result = fitNode(c, n.typ, result)
# optimization has been applied so check again:

View File

@@ -102,7 +102,7 @@ proc getIdent*(identifier: string): PIdent =
proc getIdent*(identifier: string, h: THash): PIdent =
result = getIdent(cstring(identifier), len(identifier), h)
proc IdentEq*(id: PIdent, name: string): bool =
proc identEq*(id: PIdent, name: string): bool =
result = id.id == getIdent(name).id
var idAnon* = getIdent":anonymous"

View File

@@ -19,12 +19,12 @@ const
when debugIds:
import intsets
var usedIds = InitIntSet()
var usedIds = initIntSet()
proc registerID*(id: PIdObj) =
when debugIDs:
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
InternalError("ID already used: " & $id.id)
when debugIds:
if id.id == -1 or containsOrIncl(usedIds, id.id):
internalError("ID already used: " & $id.id)
proc getID*(): int {.inline.} =
result = gFrontEndId
@@ -37,8 +37,8 @@ proc backendId*(): int {.inline.} =
proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1)
proc IDsynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
proc idSynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
proc toGid(f: string): string =
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
@@ -49,7 +49,7 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
f.writeln($gFrontEndId)
f.writeln($gBackEndId)
f.writeln($gBackendId)
f.close()
proc loadMaxIds*(project: string) =
@@ -61,5 +61,5 @@ proc loadMaxIds*(project: string) =
if f.readLine(line):
var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId)
gBackEndId = max(gBackEndId, backEndId)
gBackendId = max(gBackendId, backEndId)
f.close()

View File

@@ -22,7 +22,7 @@ proc getModuleName*(n: PNode): string =
# The proc won't perform any checks that the path is actually valid
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = UnixToNativePath(n.strVal)
result = unixToNativePath(n.strVal)
of nkIdent:
result = n.ident.s
of nkSym:
@@ -50,7 +50,7 @@ proc checkModuleName*(n: PNode): int32 =
let modulename = n.getModuleName
let fullPath = findModule(modulename, n.info.toFullPath)
if fullPath.len == 0:
LocalError(n.info, errCannotOpenFile, modulename)
localError(n.info, errCannotOpenFile, modulename)
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
@@ -59,32 +59,32 @@ proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be
# pointless in practice. So importing stubs is fine here!
# check if we have already a symbol of the same name:
var check = StrTableGet(c.importTable.symbols, s.name)
var check = strTableGet(c.importTable.symbols, s.name)
if check != nil and check.id != s.id:
if s.kind notin OverloadableSyms:
# s and check need to be qualified:
Incl(c.AmbiguousSymbols, s.id)
Incl(c.AmbiguousSymbols, check.id)
incl(c.ambiguousSymbols, s.id)
incl(c.ambiguousSymbols, check.id)
# thanks to 'export' feature, it could be we import the same symbol from
# multiple sources, so we need to call 'StrTableAdd' here:
StrTableAdd(c.importTable.symbols, s)
strTableAdd(c.importTable.symbols, s)
if s.kind == skType:
var etyp = s.typ
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
for j in countup(0, sonsLen(etyp.n) - 1):
var e = etyp.n.sons[j].sym
if e.Kind != skEnumField:
InternalError(s.info, "rawImportSymbol")
if e.kind != skEnumField:
internalError(s.info, "rawImportSymbol")
# BUGFIX: because of aliases for enums the symbol may already
# have been put into the symbol table
# BUGFIX: but only iff they are the same symbols!
var it: TIdentIter
check = InitIdentIter(it, c.importTable.symbols, e.name)
check = initIdentIter(it, c.importTable.symbols, e.name)
while check != nil:
if check.id == e.id:
e = nil
break
check = NextIdentIter(it, c.importTable.symbols)
check = nextIdentIter(it, c.importTable.symbols)
if e != nil:
rawImportSymbol(c, e)
else:
@@ -94,36 +94,36 @@ proc rawImportSymbol(c: PContext, s: PSym) =
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerAcc(n)
let s = StrTableGet(fromMod.tab, ident)
let s = strTableGet(fromMod.tab, ident)
if s == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
else:
if s.kind == skStub: loadStub(s)
if s.Kind notin ExportableSymKinds:
InternalError(n.info, "importSymbol: 2")
if s.kind notin ExportableSymKinds:
internalError(n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers
case s.Kind
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
case s.kind
of skProcKinds:
# for a overloadable syms add all overloaded routines
var it: TIdentIter
var e = InitIdentIter(it, fromMod.tab, s.name)
var e = initIdentIter(it, fromMod.tab, s.name)
while e != nil:
if e.name.id != s.Name.id: InternalError(n.info, "importSymbol: 3")
if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
rawImportSymbol(c, e)
e = NextIdentIter(it, fromMod.tab)
e = nextIdentIter(it, fromMod.tab)
else: rawImportSymbol(c, s)
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
var i: TTabIter
var s = InitTabIter(i, fromMod.tab)
var s = initTabIter(i, fromMod.tab)
while s != nil:
if s.kind != skModule:
if s.kind != skEnumField:
if s.Kind notin ExportableSymKinds:
InternalError(s.info, "importAllSymbols: " & $s.kind)
if s.kind notin ExportableSymKinds:
internalError(s.info, "importAllSymbols: " & $s.kind)
if exceptSet.empty or s.name.id notin exceptSet:
rawImportSymbol(c, s)
s = NextIter(i, fromMod.tab)
s = nextIter(i, fromMod.tab)
proc importAllSymbols*(c: PContext, fromMod: PSym) =
var exceptSet: TIntSet
@@ -160,7 +160,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
if f != InvalidFileIDX:
result = importModuleAs(n, gImportModule(c.module, f))
if sfDeprecated in result.flags:
Message(n.info, warnDeprecated, result.name.s)
message(n.info, warnDeprecated, result.name.s)
proc evalImport(c: PContext, n: PNode): PNode =
result = n

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -64,7 +64,7 @@ type
options: TOptions
module: BModule
g: PGlobals
BeforeRetNeeded: bool
beforeRetNeeded: bool
target: TTarget # duplicated here for faster dispatching
unique: int # for temp identifier generation
blocks: seq[TBlock]
@@ -111,7 +111,7 @@ proc mapType(typ: PType): TJSTypeKind =
let t = skipTypes(typ, abstractInst)
case t.kind
of tyVar, tyRef, tyPtr:
if skipTypes(t.sons[0], abstractInst).kind in mappedToObject:
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
result = etyObject
else:
result = etyBaseIndex
@@ -129,8 +129,9 @@ proc mapType(typ: PType): TJSTypeKind =
tyVarargs:
result = etyObject
of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClasses:
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
result = etyNone
of tyProc: result = etyProc
of tyCString: result = etyString
@@ -142,7 +143,7 @@ proc mangle(name: string): string =
of 'A'..'Z':
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
of '_':
nil
discard
of 'a'..'z', '0'..'9':
add(result, name[i])
else: add(result, 'X' & toHex(ord(name[i]), 2))
@@ -175,7 +176,7 @@ proc useMagic(p: PProc, name: string) =
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
# we're picky here for the system module too:
if p.prc != nil: GlobalError(p.prc.info, errSystemNeeds, name)
if p.prc != nil: globalError(p.prc.info, errSystemNeeds, name)
else: rawMessage(errSystemNeeds, name)
proc isSimpleExpr(n: PNode): bool =
@@ -240,7 +241,7 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
type
TMagicFrmt = array[0..3, string]
TMagicOps = array[mAddi..mStrToStr, TMagicFrmt]
TMagicOps = array[mAddI..mStrToStr, TMagicFrmt]
const # magic checked op; magic unchecked op; checked op; unchecked op
jsOps: TMagicOps = [
@@ -274,11 +275,11 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
["AddU", "AddU", "AddU($1, $2)", "AddU($1, $2)"], # AddU
["SubU", "SubU", "SubU($1, $2)", "SubU($1, $2)"], # SubU
["MulU", "MulU", "MulU($1, $2)", "MulU($1, $2)"], # MulU
["DivU", "DivU", "DivU($1, $2)", "DivU($1, $2)"], # DivU
["ModU", "ModU", "ModU($1, $2)", "ModU($1, $2)"], # ModU
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
["subU", "subU", "subU($1, $2)", "subU($1, $2)"], # subU
["mulU", "mulU", "mulU($1, $2)", "mulU($1, $2)"], # mulU
["divU", "divU", "divU($1, $2)", "divU($1, $2)"], # divU
["modU", "modU", "modU($1, $2)", "modU($1, $2)"], # modU
["", "", "($1 == $2)", "($1 == $2)"], # EqI
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
["", "", "($1 < $2)", "($1 < $2)"], # LtI
@@ -288,10 +289,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 == $2)", "($1 == $2)"], # EqF64
["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
["", "", "($1 < $2)", "($1 < $2)"], # LtF64
["LeU", "LeU", "LeU($1, $2)", "LeU($1, $2)"], # LeU
["LtU", "LtU", "LtU($1, $2)", "LtU($1, $2)"], # LtU
["LeU64", "LeU64", "LeU64($1, $2)", "LeU64($1, $2)"], # LeU64
["LtU64", "LtU64", "LtU64($1, $2)", "LtU64($1, $2)"], # LtU64
["leU", "leU", "leU($1, $2)", "leU($1, $2)"], # leU
["ltU", "ltU", "ltU($1, $2)", "ltU($1, $2)"], # ltU
["leU64", "leU64", "leU64($1, $2)", "leU64($1, $2)"], # leU64
["ltU64", "ltU64", "ltU64($1, $2)", "ltU64($1, $2)"], # ltU64
["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
@@ -308,10 +309,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 != $2)", "($1 != $2)"], # Xor
["", "", "($1 == $2)", "($1 == $2)"], # EqProc
["NegInt", "", "NegInt($1)", "-($1)"], # UnaryMinusI
["NegInt64", "", "NegInt64($1)", "-($1)"], # UnaryMinusI64
["AbsInt", "", "AbsInt($1)", "Math.abs($1)"], # AbsI
["AbsInt64", "", "AbsInt64($1)", "Math.abs($1)"], # AbsI64
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
["", "", "!($1)", "!($1)"], # Not
["", "", "+($1)", "+($1)"], # UnaryPlusI
["", "", "~($1)", "~($1)"], # BitnotI
@@ -326,9 +327,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
["ToU8", "ToU8", "ToU8($1)", "ToU8($1)"], # ToU8
["ToU16", "ToU16", "ToU16($1)", "ToU16($1)"], # ToU16
["ToU32", "ToU32", "ToU32($1)", "ToU32($1)"], # ToU32
["toU8", "toU8", "toU8($1)", "toU8($1)"], # toU8
["toU16", "toU16", "toU16($1)", "toU16($1)"], # toU16
["toU32", "toU32", "toU32($1)", "toU32($1)"], # toU32
["", "", "$1", "$1"], # ToFloat
["", "", "$1", "$1"], # ToBiggestFloat
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
@@ -374,11 +375,11 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
["AddU", "AddU", "AddU($1, $2)", "AddU($1, $2)"], # AddU
["SubU", "SubU", "SubU($1, $2)", "SubU($1, $2)"], # SubU
["MulU", "MulU", "MulU($1, $2)", "MulU($1, $2)"], # MulU
["DivU", "DivU", "DivU($1, $2)", "DivU($1, $2)"], # DivU
["ModU", "ModU", "ModU($1, $2)", "ModU($1, $2)"], # ModU
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
["subU", "subU", "subU($1, $2)", "subU($1, $2)"], # subU
["mulU", "mulU", "mulU($1, $2)", "mulU($1, $2)"], # mulU
["divU", "divU", "divU($1, $2)", "divU($1, $2)"], # divU
["modU", "modU", "modU($1, $2)", "modU($1, $2)"], # modU
["", "", "($1 == $2)", "($1 == $2)"], # EqI
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
["", "", "($1 < $2)", "($1 < $2)"], # LtI
@@ -388,10 +389,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 == $2)", "($1 == $2)"], # EqF64
["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
["", "", "($1 < $2)", "($1 < $2)"], # LtF64
["LeU", "LeU", "LeU($1, $2)", "LeU($1, $2)"], # LeU
["LtU", "LtU", "LtU($1, $2)", "LtU($1, $2)"], # LtU
["LeU64", "LeU64", "LeU64($1, $2)", "LeU64($1, $2)"], # LeU64
["LtU64", "LtU64", "LtU64($1, $2)", "LtU64($1, $2)"], # LtU64
["leU", "leU", "leU($1, $2)", "leU($1, $2)"], # leU
["ltU", "ltU", "ltU($1, $2)", "ltU($1, $2)"], # ltU
["leU64", "leU64", "leU64($1, $2)", "leU64($1, $2)"], # leU64
["ltU64", "ltU64", "ltU64($1, $2)", "ltU64($1, $2)"], # ltU64
["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
@@ -408,10 +409,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 != $2)", "($1 != $2)"], # Xor
["", "", "($1 == $2)", "($1 == $2)"], # EqProc
["NegInt", "", "NegInt($1)", "-($1)"], # UnaryMinusI
["NegInt64", "", "NegInt64($1)", "-($1)"], # UnaryMinusI64
["AbsInt", "", "AbsInt($1)", "Math.abs($1)"], # AbsI
["AbsInt64", "", "AbsInt64($1)", "Math.abs($1)"], # AbsI64
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
["", "", "not ($1)", "not ($1)"], # Not
["", "", "+($1)", "+($1)"], # UnaryPlusI
["", "", "~($1)", "~($1)"], # BitnotI
@@ -426,9 +427,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
["ToU8", "ToU8", "ToU8($1)", "ToU8($1)"], # ToU8
["ToU16", "ToU16", "ToU16($1)", "ToU16($1)"], # ToU16
["ToU32", "ToU32", "ToU32($1)", "ToU32($1)"], # ToU32
["toU8", "toU8", "toU8($1)", "toU8($1)"], # toU8
["toU16", "toU16", "toU16($1)", "toU16($1)"], # toU16
["toU32", "toU32", "toU32($1)", "toU32($1)"], # toU32
["", "", "$1", "$1"], # ToFloat
["", "", "$1", "$1"], # ToBiggestFloat
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
@@ -485,14 +486,14 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
proc genLineDir(p: PProc, n: PNode) =
let line = toLinenumber(n.info)
if optLineDir in p.Options:
if optLineDir in p.options:
appf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
[toRope(toFilename(n.info)), toRope(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):
useMagic(p, "endb")
appf(p.body, "endb($1);$n", [toRope(line)])
elif ({optLineTrace, optStackTrace} * p.Options ==
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
((p.prc == nil) or not (sfPure in p.prc.flags)):
appf(p.body, "F.line = $1;$n", [toRope(line)])
@@ -504,7 +505,7 @@ proc genWhileStmt(p: PProc, n: PNode) =
genLineDir(p, n)
inc(p.unique)
var length = len(p.blocks)
setlen(p.blocks, length + 1)
setLen(p.blocks, length + 1)
p.blocks[length].id = -p.unique
p.blocks[length].isLoop = true
let labl = p.unique.toRope
@@ -514,7 +515,7 @@ proc genWhileStmt(p: PProc, n: PNode) =
[cond.res, labl])
genStmt(p, n.sons[1])
appf(p.body, "}$n" | "end ::L$#::$n", [labl])
setlen(p.blocks, length)
setLen(p.blocks, length)
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
if src.kind != resNone:
@@ -555,7 +556,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
"var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
"local $1 = pcall(",
[safePoint])
if optStackTrace in p.Options: app(p.body, "framePtr = F;" & tnl)
if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl)
appf(p.body, "try {$n" | "function()$n")
var length = sonsLen(n)
var a: TCompRes
@@ -579,7 +580,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
useMagic(p, "isObj")
for j in countup(0, blen - 2):
if n.sons[i].sons[j].kind != nkType:
InternalError(n.info, "genTryStmt")
internalError(n.info, "genTryStmt")
if orExpr != nil: app(orExpr, "||" | " or ")
appf(orExpr, "isObj($1.exc.m_type, $2)",
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
@@ -641,13 +642,13 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
while v.intVal <= e.sons[1].intVal:
gen(p, v, cond)
appf(p.body, "case $1: ", [cond.rdLoc])
Inc(v.intVal)
inc(v.intVal)
else:
if stringSwitch:
case e.kind
of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ",
[makeJSString(e.strVal)])
else: InternalError(e.info, "jsgen.genCaseStmt: 2")
else: internalError(e.info, "jsgen.genCaseStmt: 2")
else:
gen(p, e, cond)
appf(p.body, "case $1: ", [cond.rdLoc])
@@ -694,7 +695,7 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
case e.kind
of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)",
[tmp, makeJSString(e.strVal)])
else: InternalError(e.info, "jsgen.genCaseStmt: 2")
else: internalError(e.info, "jsgen.genCaseStmt: 2")
else:
gen(p, e, cond)
appf(p.body, "$1 == $2", [tmp, cond.rdLoc])
@@ -713,17 +714,17 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
let idx = len(p.blocks)
if n.sons[0].kind != nkEmpty:
# named block?
if (n.sons[0].kind != nkSym): InternalError(n.info, "genBlock")
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
var sym = n.sons[0].sym
sym.loc.k = locOther
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
let labl = p.unique
appf(p.body, "L$1: do {$n" | "", labl.toRope)
gen(p, n.sons[1], r)
appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope)
setlen(p.blocks, idx)
setLen(p.blocks, idx)
proc genBreakStmt(p: PProc, n: PNode) =
var idx: int
@@ -739,7 +740,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
idx = len(p.blocks) - 1
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
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
appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)])
@@ -747,10 +748,10 @@ proc genAsmStmt(p: PProc, n: PNode) =
genLineDir(p, n)
assert(n.kind == nkAsmStmt)
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].Kind
case n.sons[i].kind
of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
of nkSym: app(p.body, mangleName(n.sons[i].sym))
else: InternalError(n.sons[i].info, "jsgen: genAsmStmt()")
else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes
@@ -811,8 +812,8 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
if needsNoCopy(y) or noCopyNeeded:
appf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "NimCopy")
appf(p.body, "$1 = NimCopy($2, $3);$n",
useMagic(p, "nimCopy")
appf(p.body, "$1 = nimCopy($2, $3);$n",
[a.res, b.res, genTypeInfo(p, y.typ)])
of etyBaseIndex:
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
@@ -851,7 +852,7 @@ proc getFieldPosition(f: PNode): int =
case f.kind
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
of nkSym: result = f.sym.position
else: InternalError(f.info, "genFieldPosition")
else: internalError(f.info, "genFieldPosition")
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
@@ -861,11 +862,11 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
else:
if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr")
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
var f = b.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
r.res = makeJSString(ropeToStr(f.loc.r))
InternalAssert a.typ != etyBaseIndex
internalAssert a.typ != etyBaseIndex
r.address = a.res
r.kind = resExpr
@@ -875,7 +876,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope])
else:
if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr")
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAddr")
var f = n.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
r.res = ropef("$1.$2", [r.res, f.loc.r])
@@ -890,14 +891,14 @@ proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes
first: biggestInt
first: BiggestInt
r.typ = etyBaseIndex
gen(p, n.sons[0], a)
gen(p, n.sons[1], b)
InternalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
r.address = a.res
var typ = skipTypes(n.sons[0].typ, abstractPtrs)
if typ.kind in {tyArray, tyArrayConstr}: first = FirstOrd(typ.sons[0])
if typ.kind in {tyArray, tyArrayConstr}: first = firstOrd(typ.sons[0])
else: first = 0
if optBoundsCheck in p.options and not isConstExpr(n.sons[1]):
useMagic(p, "chckIndx")
@@ -911,16 +912,16 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
tyVarargs:
genArrayAddr(p, n, r)
of tyTuple:
genFieldAddr(p, n, r)
else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = etyNone
if r.res == nil: InternalError(n.info, "genArrayAccess")
if r.res == nil: internalError(n.info, "genArrayAccess")
r.res = ropef("$1[$2]", [r.address, r.res])
r.address = nil
r.kind = resExpr
@@ -929,7 +930,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case n.sons[0].kind
of nkSym:
let s = n.sons[0].sym
if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
if s.loc.r == nil: internalError(n.info, "genAddr: 3")
case s.kind
of skVar, skLet, skResult:
r.kind = resExpr
@@ -948,30 +949,30 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
r.address = s.loc.r
r.res = toRope("0")
else:
InternalError(n.info, "genAddr: 4")
else: InternalError(n.info, "genAddr: 2")
internalError(n.info, "genAddr: 4")
else: internalError(n.info, "genAddr: 2")
of nkCheckedFieldExpr:
genCheckedFieldAddr(p, n, r)
of nkDotExpr:
genFieldAddr(p, n, r)
of nkBracketExpr:
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
tyVarargs:
genArrayAddr(p, n, r)
of tyTuple:
genFieldAddr(p, n, r)
else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: InternalError(n.info, "genAddr")
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(n.info, "genAddr")
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var s = n.sym
case s.kind
of skVar, skLet, skParam, skTemp, skResult:
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)
var k = mapType(s.typ)
if k == etyBaseIndex:
r.typ = etyBaseIndex
@@ -988,17 +989,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
of skConst:
genConstant(p, s)
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)
r.res = s.loc.r
of skProc, skConverter, skMethod:
discard mangleName(s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone or
{sfImportc, sfInfixCall} * s.flags != {}:
nil
discard
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
# we cannot produce code for the dispatcher yet:
nil
discard
elif sfForward in s.flags:
p.g.forwarded.add(s)
elif not p.g.generatedSyms.containsOrIncl(s.id):
@@ -1010,7 +1011,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else: app(p.g.code, newp)
else:
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)
r.res = s.loc.r
r.kind = resVal
@@ -1020,7 +1021,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
else:
var a: TCompRes
gen(p, n.sons[0], a)
if a.typ != etyBaseIndex: InternalError(n.info, "genDeref")
if a.typ != etyBaseIndex: internalError(n.info, "genDeref")
r.res = ropef("$1[$2]", [a.address, a.res])
proc genArg(p: PProc, n: PNode, r: var TCompRes) =
@@ -1051,7 +1052,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[1], r)
if r.typ == etyBaseIndex:
if r.address == nil:
GlobalError(n.info, "cannot invoke with infix syntax")
globalError(n.info, "cannot invoke with infix syntax")
r.res = ropef("$1[$2]", [r.address, r.res])
r.address = nil
r.typ = etyNone
@@ -1093,7 +1094,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope =
app(result, ": ")
app(result, createVar(p, rec.sym.typ, false))
inc(c)
else: InternalError(rec.info, "createRecordVarAux")
else: internalError(rec.info, "createRecordVarAux")
proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
var t = skipTypes(typ, abstractInst)
@@ -1112,8 +1113,8 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
var length = int(lengthOrd(t))
var e = elemType(t)
if length > 32:
useMagic(p, "ArrayConstr")
result = ropef("ArrayConstr($1, $2, $3)", [toRope(length),
useMagic(p, "arrayConstr")
result = ropef("arrayConstr($1, $2, $3)", [toRope(length),
createVar(p, e, false), genTypeInfo(p, e)])
else:
result = toRope("[")
@@ -1125,7 +1126,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
app(result, "]")
of tyTuple:
result = toRope("{")
for i in 0.. <t.sonslen:
for i in 0.. <t.sonsLen:
if i > 0: app(result, ", ")
appf(result, "Field$1: $2" | "Field$# = $#", i.toRope,
createVar(p, t.sons[i], false))
@@ -1153,7 +1154,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
proc isIndirect(v: PSym): bool =
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
v.kind notin {skProc, skConverter, skMethod, skIterator}
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
proc genVarInit(p: PProc, v: PSym, n: PNode) =
var
@@ -1170,10 +1171,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
if needsNoCopy(n):
s = a.res
else:
useMagic(p, "NimCopy")
s = ropef("NimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
useMagic(p, "nimCopy")
s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
of etyBaseIndex:
if (a.typ != etyBaseIndex): InternalError(n.info, "genVarInit")
if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
if {sfAddrTaken, sfGlobal} * v.flags != {}:
appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
[v.loc.r, a.address, a.res])
@@ -1227,7 +1228,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
case skipTypes(n.sons[1].typ, abstractVar).kind
of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)")
else: InternalError(n.info, "genOrd")
else: internalError(n.info, "genOrd")
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
@@ -1293,20 +1294,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
case op
of mOr: genOr(p, n.sons[1], n.sons[2], r)
of mAnd: genAnd(p, n.sons[1], n.sons[2], r)
of mAddi..mStrToStr: arith(p, n, r, op)
of mAddI..mStrToStr: arith(p, n, r, op)
of mRepr: genRepr(p, n, r)
of mSwap: genSwap(p, n)
of mUnaryLt:
# XXX: range checking?
if not (optOverflowCheck in p.Options): unaryExpr(p, n, r, "", "$1 - 1")
if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
of mPred:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 - $2")
if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
of mSucc:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 - $2")
if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)")
of mAppendStrStr:
@@ -1335,10 +1336,10 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
else:
unaryExpr(p, n, r, "", "($1.length-1)")
of mInc:
if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 += $2")
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
of ast.mDec:
if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 -= $2")
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = ($2)-1")
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2")
@@ -1416,7 +1417,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
for i in countup(1, sonsLen(n) - 1):
if i > 0: app(r.res, ", ")
var it = n.sons[i]
InternalAssert it.kind == nkExprColonExpr
internalAssert it.kind == nkExprColonExpr
gen(p, it.sons[1], a)
var f = it.sons[0].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
@@ -1451,7 +1452,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0].sons[0], r)
else:
gen(p, n.sons[0], r)
if r.res == nil: InternalError(n.info, "convStrToCStr")
if r.res == nil: internalError(n.info, "convStrToCStr")
useMagic(p, "toJSStr")
r.res = ropef("toJSStr($1)", [r.res])
r.kind = resExpr
@@ -1463,14 +1464,14 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0].sons[0], r)
else:
gen(p, n.sons[0], r)
if r.res == nil: InternalError(n.info, "convCStrToStr")
if r.res == nil: internalError(n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr")
r.res = ropef("cstrToNimstr($1)", [r.res])
r.kind = resExpr
proc genReturnStmt(p: PProc, n: PNode) =
if p.procDef == nil: InternalError(n.info, "genReturnStmt")
p.BeforeRetNeeded = true
if p.procDef == nil: internalError(n.info, "genReturnStmt")
p.beforeRetNeeded = true
if (n.sons[0].kind != nkEmpty):
genStmt(p, n.sons[0])
else:
@@ -1543,7 +1544,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = toRope(n.intVal)
of nkNilLit:
if isEmptyType(n.typ):
nil
discard
elif mapType(n.typ) == etyBaseIndex:
r.typ = etyBaseIndex
r.address = toRope"null" | toRope"nil"
@@ -1564,7 +1565,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
elif f == 0.5 * f:
if f > 0.0: r.res = toRope"Infinity"
else: r.res = toRope"-Infinity"
else: r.res = toRope(f.ToStrMaxPrecision)
else: r.res = toRope(f.toStrMaxPrecision)
of nkCallKinds:
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
genMagic(p, n, r)
@@ -1591,15 +1592,14 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkChckRange: genRangeChck(p, n, r, "chckRange")
of nkStringToCString: convStrToCStr(p, n, r)
of nkCStringToString: convCStrToStr(p, n, r)
of nkEmpty: nil
of nkEmpty: discard
of nkLambdaKinds:
let s = n.sons[namePos].sym
discard mangleName(s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone: nil
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
app(p.locals, genProc(p, s))
of nkMetaNode: gen(p, n.sons[0], r)
of nkType: r.res = genTypeInfo(p, n.typ)
of nkStmtList, nkStmtListExpr:
# this shows the distinction is nice for backends and should be kept
@@ -1613,7 +1613,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkIfStmt, nkIfExpr: genIf(p, n, r)
of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection: nil
of nkConstSection: discard
of nkForStmt, nkParForStmt:
internalError(n.info, "for statement not eliminated")
of nkCaseStmt:
@@ -1632,7 +1632,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
of nkProcDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
@@ -1640,7 +1640,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = nil
of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented")
else: InternalError(n.info, "gen: unknown node type: " & $n.kind)
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals
@@ -1651,11 +1651,11 @@ proc newModule(module: PSym): BModule =
proc genHeader(): PRope =
result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
"/* (c) 2013 Andreas Rumpf */$n$n" &
"/* (c) 2014 Andreas Rumpf */$n$n" &
"$nvar Globals = this;$n" &
"var framePtr = null;$n" &
"var excHandler = null;$n",
[toRope(versionAsString)])
[toRope(VersionAsString)])
proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options:
@@ -1671,7 +1671,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
result = n
var m = BModule(b)
if m.module == nil: InternalError(n.info, "myProcess")
if m.module == nil: internalError(n.info, "myProcess")
var p = newProc(globals, m, nil, m.module.options)
genModule(p, n)
app(p.g.code, p.locals)
@@ -1702,7 +1702,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
InternalError("symbol files are not possible with the JS code generator")
internalError("symbol files are not possible with the JS code generator")
result = nil
proc myOpen(s: PSym): PPassContext =

View File

@@ -37,7 +37,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
[mangleName(field), s, makeJSString(field.name.s)])
of nkRecCase:
length = sonsLen(n)
if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields")
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
field = n.sons[0].sym
s = genTypeInfo(p, field.typ)
for i in countup(1, length - 1):
@@ -98,7 +98,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
let length = sonsLen(typ.n)
var s: PRope = nil
for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym
if i > 0: app(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
@@ -119,7 +119,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
var t = typ
if t.kind == tyGenericInst: t = lastSon(t)
result = ropef("NTI$1", [toRope(t.id)])
if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind
of tyDistinct:
result = genTypeInfo(p, typ.sons[0])
@@ -134,7 +134,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
[result, toRope(ord(t.kind))])
prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.sons[0])])
[result, genTypeInfo(p, typ.lastSon)])
of tyArrayConstr, tyArray:
var s = ropef(
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
@@ -145,4 +145,4 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -11,7 +11,7 @@
import
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, rodread
idents, renderer, types, magicsys, rodread, lowerings
discard """
The basic approach is that captured vars need to be put on the heap and
@@ -116,26 +116,119 @@ type
TDep = tuple[e: PEnv, field: PSym]
TEnv {.final.} = object of TObject
attachedNode: PNode
closure: PSym # if != nil it is a used environment
createdVar: PSym # if != nil it is a used environment
createdVarComesFromIter: bool
capturedVars: seq[PSym] # captured variables in this environment
deps: seq[TDep] # dependencies
deps: seq[TDep] # dependencies
up: PEnv
tup: PType
obj: PType
TInnerContext {.final.} = object
TInnerContext = object
fn: PSym
closureParam: PSym
localsToAccess: TIdNodeTable
TOuterContext {.final.} = object
TOuterContext = object
fn: PSym # may also be a module!
currentEnv: PEnv
isIter: bool # first class iterator?
capturedVars, processed: TIntSet
localsToEnv: TIdTable # PSym->PEnv mapping
localsToAccess: TIdNodeTable
lambdasToEnv: TIdTable # PSym->PEnv mapping
up: POuterContext
closureParam, state, resultSym: PSym # only if isIter
obj: PType # only if isIter
proc createObj(owner: PSym, info: TLineInfo): PType =
result = newType(tyObject, owner)
rawAddSon(result, nil)
incl result.flags, tfFinal
result.n = newNodeI(nkRecList, info)
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc createStateField(iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = getStateType(iter)
proc newIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
#echo "produced environment: ", param.id, " for ", routine.name.s
proc getHiddenParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
assert hidden.kind == nkSym
result = hidden.sym
proc getEnvParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
proc addField(obj: PType; s: PSym) =
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field))
proc initIterContext(c: POuterContext, iter: PSym) =
c.fn = iter
c.capturedVars = initIntSet()
var cp = getEnvParam(iter)
if cp == nil:
c.obj = createObj(iter, iter.info)
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.obj)
addHiddenParam(iter, cp)
c.state = createStateField(iter)
addField(c.obj, c.state)
else:
c.obj = cp.typ.sons[0]
assert c.obj.kind == tyObject
if c.obj.n.len > 0:
c.state = c.obj.n[0].sym
else:
c.state = createStateField(iter)
addField(c.obj, c.state)
c.closureParam = cp
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
#iter.ast.add(newSymNode(c.resultSym))
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
new(result)
result.fn = fn
@@ -144,52 +237,49 @@ proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
initIdNodeTable(result.localsToAccess)
initIdTable(result.localsToEnv)
initIdTable(result.lambdasToEnv)
result.isIter = fn.kind == skClosureIterator
if result.isIter: initIterContext(result, fn)
proc newInnerContext(fn: PSym): PInnerContext =
new(result)
result.fn = fn
initIdNodeTable(result.localsToAccess)
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result)
result.deps = @[]
result.capturedVars = @[]
result.tup = newType(tyTuple, outerProc)
result.tup.n = newNodeI(nkRecList, outerProc.info)
result.obj = createObj(outerProc, outerProc.info)
result.up = up
result.attachedNode = n
proc addField(tup: PType, s: PSym) =
var field = newSym(skField, s.name, s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(tup)
addSon(tup.n, newSymNode(field))
rawAddSon(tup, t)
proc addCapturedVar(e: PEnv, v: PSym) =
for x in e.capturedVars:
if x == v: return
# XXX meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator:
if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner))
e.capturedVars.add(v)
addField(e.tup, v)
addField(e.obj, v)
proc addDep(e, d: PEnv, owner: PSym): PSym =
for x, field in items(e.deps):
if x == d: return field
var pos = sonsLen(e.tup)
var pos = sonsLen(e.obj.n)
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
result.typ = newType(tyRef, owner)
result.position = pos
assert d.tup != nil
rawAddSon(result.typ, d.tup)
addField(e.tup, result)
assert d.obj != nil
rawAddSon(result.typ, d.obj)
addField(e.obj, result)
e.deps.add((d, result))
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0]
let field = getSymFromList(deref.typ.n, b.name)
assert deref.typ.kind == tyObject
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
@@ -205,37 +295,29 @@ proc newCall(a, b: PSym): PNode =
result.add newSymNode(a)
result.add newSymNode(b)
proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
param.position = params.len
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
#echo "produced environment: ", param.id, " for ", routine.name.s
proc getHiddenParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
assert hidden.kind == nkSym
result = hidden.sym
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
result = s.kind in {skProc, skMethod, skConverter} and
result = s.kind in {skProc, skMethod, skConverter, skClosureIterator} and
s.skipGenericOwner == outerProc
#s.typ.callConv == ccClosure
proc addClosureParam(i: PInnerContext, e: PEnv) =
var cp = newSym(skParam, getIdent(paramname), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.tup)
var cp = getEnvParam(i.fn)
if cp == nil:
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.obj)
addHiddenParam(i.fn, cp)
else:
e.obj = cp.typ.sons[0]
assert e.obj.kind == tyObject
i.closureParam = cp
addHiddenParam(i.fn, i.closureParam)
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
var e = o.currentEnv
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
IdTablePut(o.lambdasToEnv, i.fn, e)
if idTableGet(o.lambdasToEnv, i.fn) == nil:
idTablePut(o.lambdasToEnv, i.fn, e)
if i.closureParam == nil: addClosureParam(i, e)
proc illegalCapture(s: PSym): bool {.inline.} =
@@ -247,13 +329,13 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
info: TLineInfo) =
# for inlined variables the owner is still wrong, so it can happen that it's
# not a captured variable at all ... *sigh*
var it = PEnv(IdTableGet(o.localsToEnv, local))
var it = PEnv(idTableGet(o.localsToEnv, local))
if it == nil: return
if illegalCapture(local) or o.fn.id != local.owner.id or
i.fn.typ.callConv notin {ccClosure, ccDefault}:
# Currently captures are restricted to a single level of nesting:
LocalError(info, errIllegalCaptureX, local.name.s)
localError(info, errIllegalCaptureX, local.name.s)
i.fn.typ.callConv = ccClosure
#echo "captureVar ", i.fn.name.s, i.fn.id, " ", local.name.s, local.id
@@ -261,11 +343,11 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
# we need to remember which inner most closure belongs to this lambda:
var e = o.currentEnv
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
IdTablePut(o.lambdasToEnv, i.fn, e)
if idTableGet(o.lambdasToEnv, i.fn) == nil:
idTablePut(o.lambdasToEnv, i.fn, e)
# variable already captured:
if IdNodeTableGet(i.localsToAccess, local) != nil: return
if idNodeTableGet(i.localsToAccess, local) != nil: return
if i.closureParam == nil: addClosureParam(i, e)
# check which environment `local` belongs to:
@@ -273,13 +355,16 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
addCapturedVar(it, local)
if it == e:
# common case: local directly in current environment:
nil
discard
else:
# it's in some upper environment:
access = indirectAccess(access, addDep(e, it, i.fn), info)
access = indirectAccess(access, local, info)
incl(o.capturedVars, local.id)
IdNodeTablePut(i.localsToAccess, local, access)
if o.isIter:
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
else:
incl(o.capturedVars, local.id)
idNodeTablePut(i.localsToAccess, local, access)
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -304,15 +389,17 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
var s = n.sym
if interestingVar(s) and i.fn.id != s.owner.id:
captureVar(o, i, s, n.info)
elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
elif s.kind in {skProc, skMethod, skConverter} and
s.skipGenericOwner == o.fn and
tfCapturesEnv in s.typ.flags and s != i.fn:
# call to some other inner proc; we need to track the dependencies for
# this:
let env = PEnv(IdTableGet(o.lambdasToEnv, i.fn))
if env == nil: InternalError(n.info, "no environment computed")
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
if env == nil: internalError(n.info, "no environment computed")
if o.currentEnv != env:
discard addDep(o.currentEnv, env, i.fn)
InternalError(n.info, "too complex environment handling required")
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
internalError(n.info, "too complex environment handling required")
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
else:
for k in countup(0, sonsLen(n) - 1):
gatherVars(o, i, n.sons[k])
@@ -349,7 +436,7 @@ proc makeClosure(prc, env: PSym, info: TLineInfo): PNode =
proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkSym:
let s = n.sym
if s == i.fn:
@@ -363,13 +450,14 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
result = makeClosure(s, i.closureParam, n.info)
else:
# captured symbol?
result = IdNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds:
result = transformInnerProc(o, i, n.sons[namePos])
result = idNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformInnerProc(o, i, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure:
# don't recurse here:
nil
discard
else:
for j in countup(0, sonsLen(n) - 1):
let x = transformInnerProc(o, i, n.sons[j])
@@ -384,7 +472,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if n == nil: return
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
nil
discard
of nkSym:
if isInnerProc(n.sym, o.fn) and not containsOrIncl(o.processed, n.sym.id):
var inner = newInnerContext(n.sym)
@@ -398,8 +486,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if inner.closureParam != nil:
let ti = transformInnerProc(o, inner, body)
if ti != nil: n.sym.ast.sons[bodyPos] = ti
of nkLambdaKinds:
searchForInnerProcs(o, n.sons[namePos])
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
searchForInnerProcs(o, n.sons[namePos])
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
# some nodes open a new scope, so they are candidates for the insertion
# of closure creation; however for simplicity we merge closures between
@@ -420,26 +509,26 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
# counts, not the block where it is captured!
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkCommentStmt: nil
if it.kind == nkCommentStmt: discard
elif it.kind == nkIdentDefs:
var L = sonsLen(it)
if it.sons[0].kind != nkSym: InternalError(it.info, "transformOuter")
if it.sons[0].kind != nkSym: internalError(it.info, "transformOuter")
#echo "set: ", it.sons[0].sym.name.s, " ", o.currentBlock == nil
IdTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
idTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
searchForInnerProcs(o, it.sons[L-1])
elif it.kind == nkVarTuple:
var L = sonsLen(it)
for j in countup(0, L-3):
#echo "set: ", it.sons[j].sym.name.s, " ", o.currentBlock == nil
IdTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
idTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
searchForInnerProcs(o, it.sons[L-1])
else:
InternalError(it.info, "transformOuter")
internalError(it.info, "transformOuter")
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure, nkTypeSection:
# don't recurse here:
# XXX recurse here and setup 'up' pointers
nil
discard
else:
for i in countup(0, sonsLen(n) - 1):
searchForInnerProcs(o, n.sons[i])
@@ -454,26 +543,20 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
result.sons[0] = le
result.sons[1] = ri
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info)
addSon(vpart, v)
addSon(vpart, ast.emptyNode)
addSon(vpart, ast.emptyNode)
addSon(father, vpart)
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed)
result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.obj)
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
if e.closure == nil:
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed)
result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.tup)
e.closure = result
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
if e.createdVar == nil:
result = newClosureCreationVar(o, e)
e.createdVar = result
else:
result = e.closure
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = e.createdVar
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
result = newNodeI(nkStmtList, env.info)
var v = newNodeI(nkVarSection, env.info)
addVar(v, newSymNode(env))
@@ -488,23 +571,130 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
# maybe later: (sfByCopy in local.flags)
# add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
# it can happen that we already captured 'local' in some other environment
# then we capture by copy for now. This is not entirely correct but better
# than nothing:
let existing = idNodeTableGet(o.localsToAccess, local)
if existing.isNil:
idNodeTablePut(o.localsToAccess, local, fieldAccess)
else:
result.add(newAsgnStmt(fieldAccess, existing, env.info))
# add support for 'up' references:
for e, field in items(scope.deps):
# add ``env.up = env2``
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
newSymNode(getClosureVar(o, e)), env.info))
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = rawClosureCreation(o, scope, env)
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
scope: PNode): PSym =
if env.createdVarComesFromIter or env.createdVar.isNil:
# we have to create a new closure:
result = newClosureCreationVar(o, env)
let cc = rawClosureCreation(o, env, result)
var insertPoint = scope.sons[0]
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
else:
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
for x in cc: insertPoint.add(x)
if env.createdVar == nil: env.createdVar = result
else:
result = env.createdVar
env.createdVarComesFromIter = true
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transformOuterProc(o: POuterContext, n: PNode): PNode
proc transformYield(c: POuterContext, n: PNode): PNode =
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transformOuterProc(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
proc transformReturn(c: POuterContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
proc outerProcSons(o: POuterContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
let iter = n.sym
assert iter.kind == skClosureIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add makeClosure(iter, env, n.info)
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if n == nil: return nil
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkSym:
var local = n.sym
var closure = PEnv(IdTableGet(o.lambdasToEnv, local))
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
return indirectAccess(newSymNode(o.closureParam), local, n.info)
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
if local.kind == skClosureIterator:
# consider: [i1, i2, i1] Since we merged the iterator's closure
# with the captured owning variables, we need to generate the
# closure generation code again:
if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
# XXX why doesn't this work?
if closure.isNil:
return liftIterSym(n)
else:
let createdVar = generateIterClosureCreation(o, closure,
closure.attachedNode)
return makeClosure(local, createdVar, n.info)
if closure != nil:
# we need to replace the lambda with '(lambda, env)':
let a = closure.closure
# we need to replace the lambda with '(lambda, env)':
let a = closure.createdVar
if a != nil:
return makeClosure(local, a, n.info)
else:
@@ -514,12 +704,12 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if scope.sons[0].kind == nkEmpty:
# change the empty node to contain the closure construction:
scope.sons[0] = generateClosureCreation(o, closure)
let x = closure.closure
let x = closure.createdVar
assert x != nil
return makeClosure(local, x, n.info)
if not contains(o.capturedVars, local.id): return
var env = PEnv(IdTableGet(o.localsToEnv, local))
var env = PEnv(idTableGet(o.localsToEnv, local))
if env == nil: return
var scope = env.attachedNode
assert scope.kind == nkStmtList
@@ -529,26 +719,55 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
# if sfByCopy notin local.flags:
result = IdNodeTableGet(o.localsToAccess, local)
result = idNodeTableGet(o.localsToAccess, local)
assert result != nil, "cannot find: " & local.name.s
# else it is captured by copy and this means that 'outer' should continue
# to access the local as a local.
of nkLambdaKinds:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkClosure:
# don't recurse here:
nil
discard
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
let x = transformOuterProc(o, n.sons[1])
if x != nil: n.sons[1] = x
result = transformOuterConv(n)
of nkYieldStmt:
if o.isIter: result = transformYield(o, n)
else: outerProcSons(o, n)
of nkReturnStmt:
if o.isIter: result = transformReturn(o, n)
else: outerProcSons(o, n)
else:
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
outerProcSons(o, n)
proc liftIterator(c: POuterContext, body: PNode): PNode =
let iter = c.fn
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transformOuterProc(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftLambdas*(fn: PSym, body: PNode): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
# ignore forward declaration:
result = body
@@ -560,16 +779,19 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
let params = fn.typ.n
for i in 1.. <params.len:
if params.sons[i].kind != nkSym:
InternalError(params.info, "liftLambdas: strange params")
internalError(params.info, "liftLambdas: strange params")
let param = params.sons[i].sym
IdTablePut(o.localsToEnv, param, o.currentEnv)
idTablePut(o.localsToEnv, param, o.currentEnv)
# put the 'result' into the environment so it can be captured:
let ast = fn.ast
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
IdTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
searchForInnerProcs(o, body)
discard transformOuterProc(o, body)
result = ex
if o.isIter:
result = liftIterator(o, ex)
else:
discard transformOuterProc(o, body)
result = ex
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
@@ -584,147 +806,6 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
# ------------------- iterator transformation --------------------------------
discard """
iterator chain[S, T](a, b: *S->T, args: *S): T =
for x in a(args): yield x
for x in b(args): yield x
let c = chain(f, g)
for x in c: echo x
# translated to:
let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
"""
type
TIterContext {.final, pure.} = object
iter, closureParam, state, resultSym: PSym
capturedVars: TIntSet
tup: PType
proc newIterResult(iter: PSym): PSym =
result = iter.ast.sons[resultPos].sym
when false:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transfIterBody(c: var TIterContext, n: PNode): PNode =
# gather used vars for closure generation
if n == nil: return nil
case n.kind
of nkSym:
var s = n.sym
if interestingIterVar(s) and c.iter.id == s.owner.id:
if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
result = indirectAccess(newSymNode(c.closureParam), s, n.info)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkYieldStmt:
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transfIterBody(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
of nkReturnStmt:
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
else:
for i in countup(0, sonsLen(n)-1):
let x = transfIterBody(c, n.sons[i])
if x != nil: n.sons[i] = x
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc liftIterator*(iter: PSym, body: PNode): PNode =
var c: TIterContext
c.iter = iter
c.capturedVars = initIntSet()
c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info)
var cp = newSym(skParam, getIdent(paramname), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup)
c.closureParam = cp
addHiddenParam(iter, cp)
c.state = newSym(skField, getIdent(":state"), iter, iter.info)
c.state.typ = getStateType(iter)
addField(c.tup, c.state)
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
iter.ast.add(newSymNode(c.resultSym))
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transfIterBody(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let iter = n.sym
assert iter.kind == skIterator
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add makeClosure(iter, env, n.info)
proc liftForLoop*(body: PNode): PNode =
# problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here:
@@ -754,17 +835,17 @@ proc liftForLoop*(body: PNode): PNode =
...
"""
var L = body.len
InternalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
internalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
var call = body[L-2]
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
# createClose()
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
# createClosure()
let iter = call[0].sym
assert iter.kind == skIterator
assert iter.kind == skClosureIterator
env = copySym(getHiddenParam(iter))
var v = newNodeI(nkVarSection, body.info)
@@ -789,7 +870,7 @@ proc liftForLoop*(body: PNode): PNode =
addSon(vpart, body[i])
addSon(vpart, ast.emptyNode) # no explicit type
if not env.isnil:
if not env.isNil:
call.sons[0] = makeClosure(call.sons[0].sym, env, body.info)
addSon(vpart, call)
addSon(v2, vpart)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -41,11 +41,12 @@ type
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
tkIs, tkIsnot, tkIterator,
tkLambda, tkLet,
tkMacro, tkMethod, tkMixin, tkUsing, tkMod, tkNil, tkNot, tkNotin,
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
tkObject, tkOf, tkOr, tkOut,
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
tkTemplate,
tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkTry, tkTuple, tkType, tkUsing,
tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkYield, # end of keywords
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
@@ -75,12 +76,13 @@ const
"finally", "for", "from", "generic", "if",
"import", "in", "include", "interface", "is", "isnot", "iterator",
"lambda", "let",
"macro", "method", "mixin", "using", "mod",
"macro", "method", "mixin", "mod",
"nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return",
"shared", "shl", "shr", "static",
"template",
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
"try", "tuple", "type", "using",
"var", "when", "while", "with", "without", "xor",
"yield",
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
"tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
@@ -99,6 +101,7 @@ type
base10, # base10 is listed as the first element,
# so that it is the correct default value
base2, base8, base16
TToken* = object # a Nimrod token
tokType*: TTokType # the type of the token
indent*: int # the indentation; != -1 if the token has been
@@ -108,6 +111,8 @@ type
fNumber*: BiggestFloat # the parsed floating point literal
base*: TNumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: int8 # leading spaces of an operator
strongSpaceB*: int8 # trailing spaces of an operator
literal*: string # the parsed (string) literal; and
# documentation comments are here too
line*, col*: int
@@ -117,7 +122,9 @@ type
indentAhead*: int # if > 0 an indendation has already been read
# this is needed because scanning comments
# needs so much look-ahead
currLineIndent*: int
strongSpaces*: bool
var gLinesCompiled*: int # all lines that have been compiled
@@ -130,11 +137,11 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
newLineInfo(L.fileIdx, tok.line, tok.col)
proc closeLexer*(lex: var TLexer)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc tokToStr*(tok: TToken): string
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
OpenLexer(lex, filename.fileInfoIdx, inputStream)
openLexer(lex, filename.fileInfoIdx, inputstream)
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
@@ -158,19 +165,20 @@ proc tokToStr*(tok: TToken): string =
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
of tkParLe..tkColon, tkEof, tkAccent:
result = tokTypeToStr[tok.tokType]
result = TokTypeToStr[tok.tokType]
else:
if tok.ident != nil:
result = tok.ident.s
else:
InternalError("tokToStr")
internalError("tokToStr")
result = ""
proc prettyTok*(tok: TToken): string =
if IsKeyword(tok.tokType): result = "keyword " & tok.ident.s
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
else: result = tokToStr(tok)
proc PrintTok*(tok: TToken) =
proc printTok*(tok: TToken) =
write(stdout, tok.line, ":", tok.col, "\t")
write(stdout, TokTypeToStr[tok.tokType])
write(stdout, " ")
writeln(stdout, tokToStr(tok))
@@ -178,18 +186,20 @@ proc PrintTok*(tok: TToken) =
var dummyIdent: PIdent
proc initToken*(L: var TToken) =
L.TokType = tkInvalid
L.tokType = tkInvalid
L.iNumber = 0
L.Indent = 0
L.indent = 0
L.strongSpaceA = 0
L.literal = ""
L.fNumber = 0.0
L.base = base10
L.ident = dummyIdent
proc fillToken(L: var TToken) =
L.TokType = tkInvalid
L.tokType = tkInvalid
L.iNumber = 0
L.Indent = 0
L.indent = 0
L.strongSpaceA = 0
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
@@ -197,26 +207,27 @@ proc fillToken(L: var TToken) =
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream)
lex.fileIdx = fileIdx
lex.fileIdx = fileidx
lex.indentAhead = - 1
inc(lex.Linenumber, inputstream.lineOffset)
lex.currLineIndent = 0
inc(lex.lineNumber, inputstream.lineOffset)
proc closeLexer(lex: var TLexer) =
inc(gLinesCompiled, lex.LineNumber)
inc(gLinesCompiled, lex.lineNumber)
closeBaseLexer(lex)
proc getColumn(L: TLexer): int =
result = getColNumber(L, L.bufPos)
result = getColNumber(L, L.bufpos)
proc getLineInfo(L: TLexer): TLineInfo =
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
msgs.Message(getLineInfo(L), msg, arg)
msgs.message(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
msgs.Message(info, msg, arg)
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
msgs.message(info, msg, arg)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
var pos = L.bufpos # use registers for pos, buf
@@ -224,7 +235,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
@@ -232,11 +243,11 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
lexMessage(L, errInvalidToken, "_")
break
add(tok.literal, '_')
Inc(pos)
L.bufPos = pos
inc(pos)
L.bufpos = pos
proc matchTwoChars(L: TLexer, first: Char, second: TCharSet): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in Second)
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
proc isFloatLiteral(s: string): bool =
for i in countup(0, len(s) - 1):
@@ -244,10 +255,10 @@ proc isFloatLiteral(s: string): bool =
return true
result = false
proc GetNumber(L: var TLexer): TToken =
proc getNumber(L: var TLexer): TToken =
var
pos, endpos: int
xi: biggestInt
xi: BiggestInt
# get the base:
result.tokType = tkIntLit # int literal until we know better
result.literal = ""
@@ -388,25 +399,25 @@ proc GetNumber(L: var TLexer): TToken =
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
inc(pos)
else: break
else: InternalError(getLineInfo(L), "getNumber")
else: internalError(getLineInfo(L), "getNumber")
case result.tokType
of tkIntLit, tkInt64Lit: result.iNumber = xi
of tkInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
of tkUInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkUInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkUInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
of tkFloat32Lit:
result.fNumber = (cast[PFloat32](addr(xi)))[]
# note: this code is endian neutral!
# XXX: Test this on big endian machine!
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
else: InternalError(getLineInfo(L), "getNumber")
else: internalError(getLineInfo(L), "getNumber")
elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
(result.tokType == tkFloat64Lit):
result.fnumber = parseFloat(result.literal)
result.fNumber = parseFloat(result.literal)
if result.tokType == tkIntLit: result.tokType = tkFloatLit
else:
result.iNumber = parseBiggestInt(result.literal)
@@ -432,7 +443,7 @@ proc handleHexChar(L: var TLexer, xi: var int) =
of 'A'..'F':
xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
inc(L.bufpos)
else: nil
else: discard
proc handleDecChars(L: var TLexer, xi: var int) =
while L.buf[L.bufpos] in {'0'..'9'}:
@@ -443,51 +454,51 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '\'
case L.buf[L.bufpos]
of 'n', 'N':
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
add(tok.literal, tnl)
Inc(L.bufpos)
inc(L.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, CR)
Inc(L.bufpos)
inc(L.bufpos)
of 'l', 'L':
add(tok.literal, LF)
Inc(L.bufpos)
inc(L.bufpos)
of 'f', 'F':
add(tok.literal, FF)
inc(L.bufpos)
of 'e', 'E':
add(tok.literal, ESC)
Inc(L.bufpos)
inc(L.bufpos)
of 'a', 'A':
add(tok.literal, BEL)
Inc(L.bufpos)
inc(L.bufpos)
of 'b', 'B':
add(tok.literal, BACKSPACE)
Inc(L.bufpos)
inc(L.bufpos)
of 'v', 'V':
add(tok.literal, VT)
Inc(L.bufpos)
inc(L.bufpos)
of 't', 'T':
add(tok.literal, Tabulator)
Inc(L.bufpos)
inc(L.bufpos)
of '\'', '\"':
add(tok.literal, L.buf[L.bufpos])
Inc(L.bufpos)
inc(L.bufpos)
of '\\':
add(tok.literal, '\\')
Inc(L.bufpos)
inc(L.bufpos)
of 'x', 'X':
inc(L.bufpos)
var xi = 0
handleHexChar(L, xi)
handleHexChar(L, xi)
add(tok.literal, Chr(xi))
add(tok.literal, chr(xi))
of '0'..'9':
if matchTwoChars(L, '0', {'0'..'9'}):
lexMessage(L, warnOctalEscape)
var xi = 0
handleDecChars(L, xi)
if (xi <= 255): add(tok.literal, Chr(xi))
if (xi <= 255): add(tok.literal, chr(xi))
else: lexMessage(L, errInvalidCharacterConstant)
else: lexMessage(L, errInvalidCharacterConstant)
@@ -497,7 +508,7 @@ proc newString(s: cstring, len: int): string =
for i in 0 .. <len:
result[i] = s[i]
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
@@ -512,21 +523,21 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR:
registerLine()
result = nimlexbase.HandleCR(L, pos)
result = nimlexbase.handleCR(L, pos)
of LF:
registerLine()
result = nimlexbase.HandleLF(L, pos)
result = nimlexbase.handleLF(L, pos)
else: result = pos
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
var pos = L.bufPos + 1 # skip "
var pos = L.bufpos + 1 # skip "
var buf = L.buf # put `buf` in a register
var line = L.linenumber # save linenumber for better error message
var line = L.lineNumber # save linenumber for better error message
if buf[pos] == '\"' and buf[pos+1] == '\"':
tok.tokType = tkTripleStrLit # long string literal:
inc(pos, 2) # skip ""
# skip leading newline:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
while true:
case buf[pos]
@@ -536,20 +547,20 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
L.bufpos = pos + 3 # skip the three """
break
add(tok.literal, '\"')
Inc(pos)
inc(pos)
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, tnl)
of nimlexbase.EndOfFile:
var line2 = L.linenumber
L.LineNumber = line
var line2 = L.lineNumber
L.lineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
L.LineNumber = line2
L.lineNumber = line2
break
else:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
# ordinary string literal
if rawMode: tok.tokType = tkRStrLit
@@ -567,23 +578,23 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
lexMessage(L, errClosingQuoteExpected)
break
elif (c == '\\') and not rawMode:
L.bufPos = pos
L.bufpos = pos
getEscapedChar(L, tok)
pos = L.bufPos
pos = L.bufpos
else:
add(tok.literal, c)
Inc(pos)
inc(pos)
L.bufpos = pos
proc getCharacter(L: var TLexer, tok: var TToken) =
Inc(L.bufpos) # skip '
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
case c
of '\0'..Pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
of '\\': getEscapedChar(L, tok)
else:
tok.literal = $c
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
inc(L.bufpos) # skip '
@@ -604,7 +615,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
lexMessage(L, errInvalidToken, "_")
break
else: break
Inc(pos)
inc(pos)
h = !$h
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
L.bufpos = pos
@@ -629,9 +640,17 @@ proc getOperator(L: var TLexer, tok: var TToken) =
while true:
var c = buf[pos]
if c notin OpChars: break
h = h !& Ord(c)
Inc(pos)
h = h !& ord(c)
inc(pos)
endOperator(L, tok, pos, h)
# advance pos but don't store it in L.bufpos so the next token (which might
# be an operator too) gets the preceeding spaces:
tok.strongSpaceB = 0
while buf[pos] == ' ':
inc pos
inc tok.strongSpaceB
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
@@ -675,22 +694,26 @@ proc scanComment(L: var TLexer, tok: var TToken) =
proc skip(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
var buf = L.buf
tok.strongSpaceA = 0
while true:
case buf[pos]
of ' ':
Inc(pos)
inc(pos)
inc(tok.strongSpaceA)
of Tabulator:
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
inc(pos)
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
var indent = 0
while buf[pos] == ' ':
Inc(pos)
Inc(indent)
inc(pos)
inc(indent)
tok.strongSpaceA = 0
if buf[pos] > ' ':
tok.indent = indent
L.currLineIndent = indent
break
else:
break # EndOfFile also leaves the loop
@@ -700,12 +723,13 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
fillToken(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
L.currLineIndent = L.indentAhead
L.indentAhead = -1
else:
tok.indent = -1
skip(L, tok)
var c = L.buf[L.bufpos]
tok.line = L.linenumber
tok.line = L.lineNumber
tok.col = getColNumber(L, L.bufpos)
if c in SymStartChars - {'r', 'R', 'l'}:
getSymbol(L, tok)
@@ -722,8 +746,8 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
else:
getOperator(L, tok)
of ',':
tok.toktype = tkComma
Inc(L.bufpos)
tok.tokType = tkComma
inc(L.bufpos)
of 'l':
# if we parsed exactly one character and its a small L (l), this
# is treated as a warning because it may be confused with the number 1
@@ -731,59 +755,59 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
lexMessage(L, warnSmallLshouldNotBeUsed)
getSymbol(L, tok)
of 'r', 'R':
if L.buf[L.bufPos + 1] == '\"':
Inc(L.bufPos)
if L.buf[L.bufpos + 1] == '\"':
inc(L.bufpos)
getString(L, tok, true)
else:
getSymbol(L, tok)
of '(':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkParDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkParDotLe
inc(L.bufpos)
else:
tok.toktype = tkParLe
tok.tokType = tkParLe
of ')':
tok.toktype = tkParRi
Inc(L.bufpos)
tok.tokType = tkParRi
inc(L.bufpos)
of '[':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkBracketDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkBracketDotLe
inc(L.bufpos)
else:
tok.toktype = tkBracketLe
tok.tokType = tkBracketLe
of ']':
tok.toktype = tkBracketRi
Inc(L.bufpos)
tok.tokType = tkBracketRi
inc(L.bufpos)
of '.':
if L.buf[L.bufPos+1] == ']':
if L.buf[L.bufpos+1] == ']':
tok.tokType = tkBracketDotRi
Inc(L.bufpos, 2)
elif L.buf[L.bufPos+1] == '}':
inc(L.bufpos, 2)
elif L.buf[L.bufpos+1] == '}':
tok.tokType = tkCurlyDotRi
Inc(L.bufpos, 2)
elif L.buf[L.bufPos+1] == ')':
inc(L.bufpos, 2)
elif L.buf[L.bufpos+1] == ')':
tok.tokType = tkParDotRi
Inc(L.bufpos, 2)
inc(L.bufpos, 2)
else:
getOperator(L, tok)
of '{':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkCurlyDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkCurlyDotLe
inc(L.bufpos)
else:
tok.toktype = tkCurlyLe
tok.tokType = tkCurlyLe
of '}':
tok.toktype = tkCurlyRi
Inc(L.bufpos)
tok.tokType = tkCurlyRi
inc(L.bufpos)
of ';':
tok.toktype = tkSemiColon
Inc(L.bufpos)
tok.tokType = tkSemiColon
inc(L.bufpos)
of '`':
tok.tokType = tkAccent
Inc(L.bufpos)
inc(L.bufpos)
of '\"':
# check for extended raw string literal:
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
@@ -802,12 +826,12 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
if c in OpChars:
getOperator(L, tok)
elif c == nimlexbase.EndOfFile:
tok.toktype = tkEof
tok.tokType = tkEof
tok.indent = 0
else:
tok.literal = $c
tok.tokType = tkInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)
dummyIdent = getIdent("")

View File

@@ -20,17 +20,17 @@ type
PStrEntry* = ref TStrEntry
TLinkedList* = object # for the "find" operation:
head*, tail*: PListEntry
Counter*: int
counter*: int
TCompareProc* = proc (entry: PListEntry, closure: Pointer): bool {.nimcall.}
TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}
proc InitLinkedList*(list: var TLinkedList) =
list.Counter = 0
proc initLinkedList*(list: var TLinkedList) =
list.counter = 0
list.head = nil
list.tail = nil
proc Append*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc append*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.next = nil
entry.prev = list.tail
if list.tail != nil:
@@ -39,7 +39,7 @@ proc Append*(list: var TLinkedList, entry: PListEntry) =
list.tail = entry
if list.head == nil: list.head = entry
proc Contains*(list: TLinkedList, data: string): bool =
proc contains*(list: TLinkedList, data: string): bool =
var it = list.head
while it != nil:
if PStrEntry(it).data == data:
@@ -50,15 +50,15 @@ proc newStrEntry(data: string): PStrEntry =
new(result)
result.data = data
proc AppendStr*(list: var TLinkedList, data: string) =
proc appendStr*(list: var TLinkedList, data: string) =
append(list, newStrEntry(data))
proc IncludeStr*(list: var TLinkedList, data: string): bool =
if Contains(list, data): return true
AppendStr(list, data) # else: add to list
proc includeStr*(list: var TLinkedList, data: string): bool =
if contains(list, data): return true
appendStr(list, data) # else: add to list
proc Prepend*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc prepend*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.prev = nil
entry.next = list.head
if list.head != nil:
@@ -67,22 +67,22 @@ proc Prepend*(list: var TLinkedList, entry: PListEntry) =
list.head = entry
if list.tail == nil: list.tail = entry
proc PrependStr*(list: var TLinkedList, data: string) =
proc prependStr*(list: var TLinkedList, data: string) =
prepend(list, newStrEntry(data))
proc InsertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
assert(pos != nil)
if pos == list.head:
prepend(list, entry)
else:
Inc(list.counter)
inc(list.counter)
entry.next = pos
entry.prev = pos.prev
if pos.prev != nil: pos.prev.next = entry
pos.prev = entry
proc Remove*(list: var TLinkedList, entry: PListEntry) =
Dec(list.counter)
proc remove*(list: var TLinkedList, entry: PListEntry) =
dec(list.counter)
if entry == list.tail:
list.tail = entry.prev
if entry == list.head:
@@ -103,14 +103,14 @@ proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
entry.next = list.head
list.head = entry
proc ExcludeStr*(list: var TLinkedList, data: string) =
proc excludeStr*(list: var TLinkedList, data: string) =
var it = list.head
while it != nil:
let nxt = it.next
if PStrEntry(it).data == data: remove(list, it)
it = nxt
proc Find*(list: TLinkedList, fn: TCompareProc, closure: Pointer): PListEntry =
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
result = list.head
while result != nil:
if fn(result, closure): return

View File

@@ -23,63 +23,63 @@ type
llsStdIn # stream encapsulates stdin
TLLStream* = object of TObject
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
f*: tfile
f*: TFile
s*: string
rd*, wr*: int # for string streams
lineOffset*: int # for fake stdin line numbers
PLLStream* = ref TLLStream
proc LLStreamOpen*(data: string): PLLStream
proc LLStreamOpen*(f: var tfile): PLLStream
proc LLStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc LLStreamOpen*(): PLLStream
proc LLStreamOpenStdIn*(): PLLStream
proc LLStreamClose*(s: PLLStream)
proc LLStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc LLStreamReadLine*(s: PLLStream, line: var string): bool
proc LLStreamReadAll*(s: PLLStream): string
proc LLStreamWrite*(s: PLLStream, data: string)
proc LLStreamWrite*(s: PLLStream, data: Char)
proc LLStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc LLStreamWriteln*(s: PLLStream, data: string)
proc llStreamOpen*(data: string): PLLStream
proc llStreamOpen*(f: var TFile): PLLStream
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc llStreamOpen*(): PLLStream
proc llStreamOpenStdIn*(): PLLStream
proc llStreamClose*(s: PLLStream)
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamReadLine*(s: PLLStream, line: var string): bool
proc llStreamReadAll*(s: PLLStream): string
proc llStreamWrite*(s: PLLStream, data: string)
proc llStreamWrite*(s: PLLStream, data: char)
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc llStreamWriteln*(s: PLLStream, data: string)
# implementation
proc LLStreamOpen(data: string): PLLStream =
proc llStreamOpen(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString
proc LLStreamOpen(f: var tfile): PLLStream =
proc llStreamOpen(f: var TFile): PLLStream =
new(result)
result.f = f
result.kind = llsFile
proc LLStreamOpen(filename: string, mode: TFileMode): PLLStream =
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
new(result)
result.kind = llsFile
if not open(result.f, filename, mode): result = nil
proc LLStreamOpen(): PLLStream =
proc llStreamOpen(): PLLStream =
new(result)
result.kind = llsNone
proc LLStreamOpenStdIn(): PLLStream =
proc llStreamOpenStdIn(): PLLStream =
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1
proc LLStreamClose(s: PLLStream) =
proc llStreamClose(s: PLLStream) =
case s.kind
of llsNone, llsString, llsStdIn:
nil
discard
of llsFile:
close(s.f)
when not defined(ReadLineFromStdin):
when not defined(readLineFromStdin):
# fallback implementation:
proc ReadLineFromStdin(prompt: string, line: var string): bool =
proc readLineFromStdin(prompt: string, line: var string): bool =
stdout.write(prompt)
result = readLine(stdin, line)
@@ -99,7 +99,7 @@ proc endsWithOpr*(x: string): bool =
result = x.endsWith(LineContinuationOprs)
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
result = inTriplestring or
result = inTripleString or
line[0] == ' ' or
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
@@ -111,12 +111,12 @@ proc countTriples(s: string): int =
inc i, 2
inc i
proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
s.s = ""
s.rd = 0
var line = newStringOfCap(120)
var triples = 0
while ReadLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
add(s.s, line)
add(s.s, "\n")
inc triples, countTriples(line)
@@ -127,7 +127,7 @@ proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
copyMem(buf, addr(s.s[s.rd]), result)
inc(s.rd, result)
proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
case s.kind
of llsNone:
result = 0
@@ -139,9 +139,9 @@ proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
of llsFile:
result = readBuffer(s.f, buf, bufLen)
of llsStdIn:
result = LLreadFromStdin(s, buf, bufLen)
result = llReadFromStdin(s, buf, bufLen)
proc LLStreamReadLine(s: PLLStream, line: var string): bool =
proc llStreamReadLine(s: PLLStream, line: var string): bool =
setLen(line, 0)
case s.kind
of llsNone:
@@ -165,25 +165,25 @@ proc LLStreamReadLine(s: PLLStream, line: var string): bool =
of llsStdIn:
result = readLine(stdin, line)
proc LLStreamWrite(s: PLLStream, data: string) =
proc llStreamWrite(s: PLLStream, data: string) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr, len(data))
of llsFile:
write(s.f, data)
proc LLStreamWriteln(s: PLLStream, data: string) =
LLStreamWrite(s, data)
LLStreamWrite(s, "\n")
proc llStreamWriteln(s: PLLStream, data: string) =
llStreamWrite(s, data)
llStreamWrite(s, "\n")
proc LLStreamWrite(s: PLLStream, data: Char) =
proc llStreamWrite(s: PLLStream, data: char) =
var c: char
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr)
@@ -191,22 +191,21 @@ proc LLStreamWrite(s: PLLStream, data: Char) =
c = data
discard writeBuffer(s.f, addr(c), sizeof(c))
proc LLStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
if bufLen > 0:
setlen(s.s, len(s.s) + bufLen)
copyMem(addr(s.s[0 + s.wr]), buf, bufLen)
inc(s.wr, bufLen)
if buflen > 0:
setLen(s.s, len(s.s) + buflen)
copyMem(addr(s.s[0 + s.wr]), buf, buflen)
inc(s.wr, buflen)
of llsFile:
discard writeBuffer(s.f, buf, bufLen)
discard writeBuffer(s.f, buf, buflen)
proc LLStreamReadAll(s: PLLStream): string =
proc llStreamReadAll(s: PLLStream): string =
const
bufSize = 2048
var bytes, i: int
case s.kind
of llsNone, llsStdIn:
result = ""
@@ -216,10 +215,10 @@ proc LLStreamReadAll(s: PLLStream): string =
s.rd = len(s.s)
of llsFile:
result = newString(bufSize)
bytes = readBuffer(s.f, addr(result[0]), bufSize)
i = bytes
var bytes = readBuffer(s.f, addr(result[0]), bufSize)
var i = bytes
while bytes == bufSize:
setlen(result, i + bufSize)
setLen(result, i + bufSize)
bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
inc(i, bytes)
setlen(result, i)
setLen(result, i)

View File

@@ -21,7 +21,7 @@ proc considerAcc*(n: PNode): PIdent =
of nkSym: result = n.sym.name
of nkAccQuoted:
case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0])
else:
var id = ""
@@ -30,16 +30,17 @@ proc considerAcc*(n: PNode): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
else: globalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id)
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
else:
GlobalError(n.info, errIdentifierExpected, renderTree(n))
globalError(n.info, errIdentifierExpected, renderTree(n))
template addSym*(scope: PScope, s: PSym) =
StrTableAdd(scope.symbols, s)
strTableAdd(scope.symbols, s)
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
if StrTableIncl(scope.symbols, s):
if strTableIncl(scope.symbols, s):
result = Failure
else:
result = Success
@@ -64,17 +65,17 @@ iterator walkScopes*(scope: PScope): PScope =
current = current.parent
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
result = StrTableGet(c.currentScope.symbols, s)
result = strTableGet(c.currentScope.symbols, s)
proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil: return
result = nil
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil and result.kind in filter: return
result = nil
@@ -91,7 +92,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors:
if gCmd != cmdInteractive:
if gCmd != cmdInteractive and c.inCompilesContext == 0:
c.importTable.addSym(result)
type
@@ -108,71 +109,74 @@ type
proc getSymRepr*(s: PSym): string =
case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
else: result = s.name.s
proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter
var s = InitTabIter(it, scope.symbols)
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
while s != nil:
if sfForward in s.flags:
# too many 'implementation of X' errors are annoying
# and slow 'suggest' down:
if missingImpls == 0:
LocalError(s.info, errImplOfXexpected, getSymRepr(s))
localError(s.info, errImplOfXexpected, getSymRepr(s))
inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
# BUGFIX: check options in s!
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = NextIter(it, scope.symbols)
# XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)
proc WrongRedefinition*(info: TLineInfo, s: string) =
proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)
proc addDecl*(c: PContext, sym: PSym) =
if c.currentScope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)
proc addPrelimDecl*(c: PContext, sym: PSym) =
discard c.currentScope.addUniqueSym(sym)
proc addDeclAt*(scope: PScope, sym: PSym) =
if scope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)
proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags:
# add to interface:
if c.module != nil: StrTableAdd(c.module.tab, sym)
else: InternalError(sym.info, "AddInterfaceDeclAux")
if c.module != nil: strTableAdd(c.module.tab, sym)
else: internalError(sym.info, "AddInterfaceDeclAux")
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addDeclAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
InternalError(fn.info, "addOverloadableSymAt")
internalError(fn.info, "addOverloadableSymAt")
return
var check = StrTableGet(scope.symbols, fn.name)
if check != nil and check.Kind notin OverloadableSyms:
WrongRedefinition(fn.info, fn.Name.s)
var check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(fn.info, fn.name.s)
else:
scope.addSym(fn)
proc addInterfaceDecl*(c: PContext, sym: PSym) =
# it adds the symbol to the interface if appropriate
addDecl(c, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
# it adds the symbol to the interface if appropriate
addOverloadableSymAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
@@ -180,7 +184,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
of nkIdent:
result = searchInScopes(c, n.ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
localError(n.info, errUndeclaredIdentifier, n.ident.s)
result = errorSym(c, n)
of nkSym:
result = n.sym
@@ -188,34 +192,34 @@ proc lookUp*(c: PContext, n: PNode): PSym =
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
else:
InternalError(n.info, "lookUp")
internalError(n.info, "lookUp")
return
if Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, result.name.s)
if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result)
type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared
proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and
Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, ident.s)
contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, ident.s)
of nkSym:
result = n.sym
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, n.sym.name.s)
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, n.sym.name.s)
of nkDotExpr:
result = nil
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
@@ -227,28 +231,31 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
ident = considerAcc(n.sons[1])
if ident != nil:
if m == c.module:
result = StrTableGet(c.topLevelScope.symbols, ident)
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = StrTableGet(m.tab, ident)
result = strTableGet(m.tab, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n.sons[1])
elif checkUndeclared in flags:
LocalError(n.sons[1].info, errIdentifierExpected,
elif n.sons[1].kind == nkSym:
result = n.sons[1].sym
elif checkUndeclared in flags and
n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
else:
result = nil
if result != nil and result.kind == skStub: loadStub(result)
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
o.scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = InitIdentIter(o.it, o.scope.symbols, ident)
result = initIdentIter(o.it, o.scope.symbols, ident)
if result != nil:
break
else:
@@ -269,12 +276,12 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if ident != nil:
if o.m == c.module:
# a module may access its private members:
result = InitIdentIter(o.it, c.topLevelScope.symbols, ident)
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
o.mode = oimSelfModule
else:
result = InitIdentIter(o.it, o.m.tab, ident)
result = initIdentIter(o.it, o.m.tab, ident)
else:
LocalError(n.sons[1].info, errIdentifierExpected,
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
@@ -282,8 +289,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sons[0].sym
o.symChoiceIndex = 1
o.inSymChoice = initIntSet()
Incl(o.inSymChoice, result.id)
else: nil
incl(o.inSymChoice, result.id)
else: discard
if result != nil and result.kind == skStub: loadStub(result)
proc lastOverloadScope*(o: TOverloadIter): int =
@@ -303,7 +310,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = InitIdentIter(o.it, o.scope.symbols, o.it.name)
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
# BUGFIX: o.it.name <-> n.ident
else:
result = nil
@@ -314,26 +321,38 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimSymChoice:
if o.symChoiceIndex < sonsLen(n):
result = n.sons[o.symChoiceIndex].sym
Incl(o.inSymChoice, result.id)
incl(o.inSymChoice, result.id)
inc o.symChoiceIndex
elif n.kind == nkOpenSymChoice:
# try 'local' symbols too for Koenig's lookup:
o.mode = oimSymChoiceLocalLookup
o.scope = c.currentScope
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
of oimSymChoiceLocalLookup:
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
if result != nil and result.kind == skStub: loadStub(result)
when false:
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
flags = {checkUndeclared}): PSym =
var o: TOverloadIter
result = initOverloadIter(o, c, n)
var a = result
while a != nil:
if sfImmediate in a.flags: return a
a = nextOverloadIter(o, c, n)
if result == nil and checkUndeclared in flags:
localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
result = errorSym(c, n)

52
compiler/lowerings.nim Normal file
View File

@@ -0,0 +1,52 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements common simple lowerings.
const
genPrefix* = ":tmp" # prefix for generated names
import ast, types, idents, magicsys
proc newTupleAccess*(tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i])
addSon(result, copyTree(tup))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
lit.intVal = i
addSon(result, lit)
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = ast.emptyNode
addSon(father, vpart)
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, value.info)
v.addVar(newSymNode(temp))
result.add(v)
result.add newAsgnStmt(newSymNode(temp), value)
for i in 0 .. n.len-3:
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))

View File

@@ -12,14 +12,14 @@
import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
var SystemModule*: PSym
var systemModule*: PSym
proc registerSysType*(t: PType)
# magic symbols in the system module:
proc getSysType*(kind: TTypeKind): PType
proc getCompilerProc*(name: string): PSym
proc registerCompilerProc*(s: PSym)
proc FinishSystem*(tab: TStrTable)
proc finishSystem*(tab: TStrTable)
proc getSysSym*(name: string): PSym
# implementation
@@ -36,7 +36,7 @@ proc newSysType(kind: TTypeKind, size: int): PType =
result.align = size
proc getSysSym(name: string): PSym =
result = StrTableGet(systemModule.tab, getIdent(name))
result = strTableGet(systemModule.tab, getIdent(name))
if result == nil:
rawMessage(errSystemNeeds, name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
@@ -46,11 +46,11 @@ proc getSysSym(name: string): PSym =
proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter
let id = getIdent(name)
result = InitIdentIter(ti, systemModule.tab, id)
result = initIdentIter(ti, systemModule.tab, id)
while result != nil:
if result.kind == skStub: loadStub(result)
if result.magic == m: return result
result = NextIdentIter(ti, systemModule.tab)
result = nextIdentIter(ti, systemModule.tab)
rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
@@ -79,14 +79,14 @@ proc getSysType(kind: TTypeKind): PType =
of tyBool: result = sysTypeFromName("bool")
of tyChar: result = sysTypeFromName("char")
of tyString: result = sysTypeFromName("string")
of tyCstring: result = sysTypeFromName("cstring")
of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(tyNil, ptrSize)
else: InternalError("request for typekind: " & $kind)
else: internalError("request for typekind: " & $kind)
gSysTypes[kind] = result
if result.kind != kind:
InternalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: InternalError("type not found: " & $kind)
internalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError("type not found: " & $kind)
var
intTypeCache: array[-5..64, PType]
@@ -126,7 +126,7 @@ proc skipIntLit*(t: PType): PType {.inline.} =
return getSysType(t.kind)
result = t
proc AddSonSkipIntLit*(father, son: PType) =
proc addSonSkipIntLit*(father, son: PType) =
if isNil(father.sons): father.sons = @[]
let s = son.skipIntLit
add(father.sons, s)
@@ -134,7 +134,7 @@ proc AddSonSkipIntLit*(father, son: PType) =
proc setIntLitType*(result: PNode) =
let i = result.intVal
case platform.IntSize
case platform.intSize
of 8: result.typ = getIntLitType(result)
of 4:
if i >= low(int32) and i <= high(int32):
@@ -158,13 +158,13 @@ proc setIntLitType*(result: PNode) =
result.typ = getSysType(tyInt32)
else:
result.typ = getSysType(tyInt64)
else: InternalError(result.info, "invalid int size")
else: internalError(result.info, "invalid int size")
proc getCompilerProc(name: string): PSym =
var ident = getIdent(name, hashIgnoreStyle(name))
result = StrTableGet(compilerprocs, ident)
result = strTableGet(compilerprocs, ident)
if result == nil:
result = StrTableGet(rodCompilerProcs, ident)
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)
@@ -172,7 +172,6 @@ proc getCompilerProc(name: string): PSym =
proc registerCompilerProc(s: PSym) =
strTableAdd(compilerprocs, s)
proc FinishSystem(tab: TStrTable) = nil
initStrTable(compilerprocs)
proc finishSystem(tab: TStrTable) = discard
initStrTable(compilerprocs)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -14,16 +14,16 @@ import
os, condsyms, rodread, rodwrite, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, evals, types, idgen,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
pretty
from magicsys import SystemModule, resetSysTypes
from magicsys import systemModule, resetSysTypes
const
has_LLVM_Backend = false
hasLLVM_Backend = false
when has_LLVM_Backend:
when hasLLVM_Backend:
import llvmgen
proc rodPass =
@@ -37,22 +37,22 @@ proc semanticPasses =
registerPass verbosePass
registerPass semPass
proc CommandGenDepend =
proc commandGenDepend =
semanticPasses()
registerPass(genDependPass)
registerPass(gendependPass)
registerPass(cleanupPass)
compileProject()
generateDot(gProjectFull)
execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
' ' & changeFileExt(gProjectFull, "dot"))
proc CommandCheck =
proc commandCheck =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses() # use an empty backend for semantic checking only
rodPass()
compileProject()
proc CommandDoc2 =
proc commandDoc2 =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(docgen2Pass)
@@ -60,7 +60,7 @@ proc CommandDoc2 =
compileProject()
finishDoc2Pass(gProjectName)
proc CommandCompileToC =
proc commandCompileToC =
semanticPasses()
registerPass(cgenPass)
rodPass()
@@ -73,7 +73,7 @@ proc CommandCompileToC =
compileProject()
cgenWriteModules()
if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
if isServing:
# caas will keep track only of the compilation commands
@@ -111,45 +111,45 @@ proc CommandCompileToC =
ccgutils.resetCaches()
GC_fullCollect()
when has_LLVM_Backend:
proc CommandCompileToLLVM =
when hasLLVM_Backend:
proc commandCompileToLLVM =
semanticPasses()
registerPass(llvmgen.llvmgenPass())
rodPass()
#registerPass(cleanupPass())
compileProject()
proc CommandCompileToJS =
proc commandCompileToJS =
#incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS)
#initDefines()
DefineSymbol("nimrod") # 'nimrod' is always defined
DefineSymbol("ecmascript") # For backward compatibility
DefineSymbol("js")
defineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("ecmascript") # For backward compatibility
defineSymbol("js")
semanticPasses()
registerPass(jsgenPass)
registerPass(JSgenPass)
compileProject()
proc InteractivePasses =
proc interactivePasses =
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines()
DefineSymbol("nimrodvm")
when hasFFI: DefineSymbol("nimffi")
defineSymbol("nimrodvm")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(evalPass)
proc CommandInteractive =
proc commandInteractive =
msgs.gErrorMax = high(int) # do not stop after first error
InteractivePasses()
interactivePasses()
compileSystemModule()
if commandArgs.len > 0:
discard CompileModule(fileInfoIdx(gProjectFull), {})
discard compileModule(fileInfoIdx(gProjectFull), {})
else:
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, LLStreamOpenStdIn(), nil)
processModule(m, llStreamOpenStdIn(), nil)
const evalPasses = [verbosePass, semPass, evalPass]
@@ -157,28 +157,28 @@ proc evalNim(nodes: PNode, module: PSym) =
carryPasses(nodes, module, evalPasses)
proc commandEval(exp: string) =
if SystemModule == nil:
InteractivePasses()
if systemModule == nil:
interactivePasses()
compileSystemModule()
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(echoExp.parseString, makeStdinModule())
proc CommandPrettyOld =
proc commandPrettyOld =
var projectFile = addFileExt(mainCommandArg(), NimExt)
var module = parseFile(projectFile.fileInfoIdx)
if module != nil:
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
proc CommandPretty =
proc commandPretty =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(prettyPass)
compileProject()
pretty.overwriteFiles()
proc CommandScan =
var f = addFileExt(mainCommandArg(), nimExt)
var stream = LLStreamOpen(f, fmRead)
proc commandScan =
var f = addFileExt(mainCommandArg(), NimExt)
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: TLexer
@@ -187,20 +187,20 @@ proc CommandScan =
openLexer(L, f, stream)
while true:
rawGetTok(L, tok)
PrintTok(tok)
printTok(tok)
if tok.tokType == tkEof: break
CloseLexer(L)
closeLexer(L)
else:
rawMessage(errCannotOpenFile, f)
proc CommandSuggest =
proc commandSuggest =
if isServing:
# XXX: hacky work-around ahead
# Currently, it's possible to issue a idetools command, before
# issuing the first compile command. This will leave the compiler
# cache in a state where "no recompilation is necessary", but the
# cgen pass was never executed at all.
CommandCompileToC()
commandCompileToC()
if gDirtyBufferIdx != 0:
discard compileModule(gDirtyBufferIdx, {sfDirty})
resetModule(gDirtyBufferIdx)
@@ -219,21 +219,21 @@ proc CommandSuggest =
proc wantMainModule =
if gProjectFull.len == 0:
if optMainModule.len == 0:
Fatal(gCmdLineInfo, errCommandExpectsFilename)
fatal(gCmdLineInfo, errCommandExpectsFilename)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc requireMainModuleOption =
if optMainModule.len == 0:
Fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc resetMemory =
resetCompilationLists()
@@ -286,7 +286,7 @@ const
SimiluateCaasMemReset = false
PrintRopeCacheStats = false
proc MainCommand* =
proc mainCommand* =
when SimiluateCaasMemReset:
gGlobalOptions.incl(optCaasEnabled)
@@ -297,7 +297,7 @@ proc MainCommand* =
if gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setID(100)
setId(100)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
case command.normalize
@@ -305,88 +305,88 @@ proc MainCommand* =
# compile means compileToC currently
gCmd = cmdCompileToC
wantMainModule()
CommandCompileToC()
commandCompileToC()
of "cpp", "compiletocpp":
extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gpp")
wantMainModule()
DefineSymbol("cpp")
CommandCompileToC()
defineSymbol("cpp")
commandCompileToC()
of "objc", "compiletooc":
extccomp.cExt = ".m"
gCmd = cmdCompileToOC
wantMainModule()
DefineSymbol("objc")
CommandCompileToC()
defineSymbol("objc")
commandCompileToC()
of "run":
gCmd = cmdRun
wantMainModule()
when hasTinyCBackend:
extccomp.setCC("tcc")
CommandCompileToC()
commandCompileToC()
else:
rawMessage(errInvalidCommandX, command)
of "js", "compiletojs":
gCmd = cmdCompileToJS
wantMainModule()
CommandCompileToJS()
commandCompileToJS()
of "compiletollvm":
gCmd = cmdCompileToLLVM
wantMainModule()
when has_LLVM_Backend:
when hasLLVM_Backend:
CommandCompileToLLVM()
else:
rawMessage(errInvalidCommandX, command)
of "pretty":
gCmd = cmdPretty
wantMainModule()
CommandPretty()
commandPretty()
of "doc":
gCmd = cmdDoc
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
CommandDoc()
commandDoc()
of "doc2":
gCmd = cmdDoc
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
DefineSymbol("nimdoc")
CommandDoc2()
defineSymbol("nimdoc")
commandDoc2()
of "rst2html":
gCmd = cmdRst2html
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
CommandRst2Html()
commandRst2Html()
of "rst2tex":
gCmd = cmdRst2tex
LoadConfigs(DocTexConfig)
loadConfigs(DocTexConfig)
wantMainModule()
CommandRst2TeX()
commandRst2TeX()
of "jsondoc":
gCmd = cmdDoc
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
DefineSymbol("nimdoc")
CommandJSON()
defineSymbol("nimdoc")
commandJSON()
of "buildindex":
gCmd = cmdDoc
LoadConfigs(DocConfig)
CommandBuildIndex()
loadConfigs(DocConfig)
commandBuildIndex()
of "gendepend":
gCmd = cmdGenDepend
wantMainModule()
CommandGenDepend()
commandGenDepend()
of "dump":
gcmd = cmdDump
if getconfigvar("dump.format") == "json":
gCmd = cmdDump
if getConfigVar("dump.format") == "json":
requireMainModuleOption()
var definedSymbols = newJArray()
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
var libpaths = newJArray()
for dir in itersearchpath(searchpaths): libpaths.elems.add(%dir)
for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir)
var dumpdata = % [
(key: "version", val: %VersionAsString),
@@ -395,17 +395,17 @@ proc MainCommand* =
(key: "lib_paths", val: libpaths)
]
outWriteLn($dumpdata)
outWriteln($dumpdata)
else:
outWriteLn("-- list of currently defined symbols --")
for s in definedSymbolNames(): outWriteLn(s)
outWriteLn("-- end of list --")
outWriteln("-- list of currently defined symbols --")
for s in definedSymbolNames(): outWriteln(s)
outWriteln("-- end of list --")
for it in iterSearchPath(searchpaths): msgWriteLn(it)
for it in iterSearchPath(searchPaths): msgWriteln(it)
of "check":
gCmd = cmdCheck
wantMainModule()
CommandCheck()
commandCheck()
of "parse":
gCmd = cmdParse
wantMainModule()
@@ -413,11 +413,11 @@ proc MainCommand* =
of "scan":
gCmd = cmdScan
wantMainModule()
CommandScan()
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
commandScan()
msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
of "i":
gCmd = cmdInteractive
CommandInteractive()
commandInteractive()
of "e":
# XXX: temporary command for easier testing
commandEval(mainCommandArg())
@@ -429,12 +429,12 @@ proc MainCommand* =
commandEval(gEvalExpr)
else:
wantMainModule()
CommandSuggest()
commandSuggest()
of "serve":
isServing = true
gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error
serve(MainCommand)
serve(mainCommand)
else:
rawMessage(errInvalidCommandX, command)
@@ -450,7 +450,8 @@ proc MainCommand* =
echo " tries : ", gCacheTries
echo " misses: ", gCacheMisses
echo " int tries: ", gCacheIntTries
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
ffDecimal, 3)
when SimiluateCaasMemReset:
resetMemory()

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -20,7 +20,7 @@ type
TModuleInMemory* = object
compiledAt*: float
crc*: TCrc32
deps*: seq[int32] ## XXX: slurped files are not currently tracked
deps*: seq[int32] ## XXX: slurped files are currently not tracked
needsRecompile*: TNeedRecompile
crcStatus*: TCrcStatus
@@ -41,7 +41,7 @@ template crc(x: PSym): expr =
gMemCacheData[x.position].crc
proc crcChanged(fileIdx: int32): bool =
InternalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
template updateStatus =
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
@@ -68,7 +68,7 @@ proc doCRC(fileIdx: int32) =
# echo "FIRST CRC: ", fileIdx.ToFilename
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
proc addDep(x: Psym, dep: int32) =
proc addDep(x: PSym, dep: int32) =
growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep)
@@ -83,7 +83,7 @@ proc resetAllModules* =
for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil:
resetModule(i.int32)
resetPackageCache()
# for m in cgenModules(): echo "CGEN MODULE FOUND"
proc checkDepMem(fileIdx: int32): TNeedRecompile =
@@ -120,8 +120,9 @@ proc newModule(fileIdx: int32): PSym =
if not isNimrodIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
result.owner = result # a module belongs to itself
result.info = newLineInfo(fileIdx, 1, 1)
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
result.info)
result.position = fileIdx
growCache gMemCacheData, fileIdx
@@ -130,7 +131,7 @@ proc newModule(fileIdx: int32): PSym =
incl(result.flags, sfUsed)
initStrTable(result.tab)
StrTableAdd(result.tab, result) # a module knows itself
strTableAdd(result.tab, result) # a module knows itself
proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
@@ -144,7 +145,7 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
InternalError("handleSymbolFile should have set the module\'s ID")
internalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
@@ -155,7 +156,7 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
doCRC fileIdx
else:
if checkDepMem(fileIdx) == Yes:
result = CompileModule(fileIdx, flags)
result = compileModule(fileIdx, flags)
else:
result = gCompiledModules[fileIdx]
@@ -164,14 +165,14 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags:
LocalError(result.info, errAttemptToRedefine, result.Name.s)
localError(result.info, errAttemptToRedefine, result.name.s)
proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx)
if optCaasEnabled in gGlobalOptions:
growCache gMemCacheData, fileIdx
addDep(s, fileIdx)
doCrc(fileIdx)
doCRC(fileIdx)
proc `==^`(a, b: string): bool =
try:
@@ -180,17 +181,17 @@ proc `==^`(a, b: string): bool =
result = false
proc compileSystemModule* =
if magicsys.SystemModule == nil:
SystemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard CompileModule(SystemFileIdx, {sfSystemModule})
if magicsys.systemModule == nil:
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard compileModule(systemFileIdx, {sfSystemModule})
proc CompileProject*(projectFile = gProjectMainIdx) =
proc compileProject*(projectFile = gProjectMainIdx) =
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
if projectFile == SystemFileIdx:
discard CompileModule(projectFile, {sfMainModule, sfSystemModule})
if projectFile == systemFileIdx:
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
compileSystemModule()
discard CompileModule(projectFile, {sfMainModule})
discard compileModule(projectFile, {sfMainModule})
var stdinModule: PSym
proc makeStdinModule*(): PSym =

View File

@@ -67,7 +67,7 @@ type
errAmbiguousCallXYZ, errWrongNumberOfArguments,
errXCannotBePassedToProcVar,
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
@@ -88,13 +88,16 @@ type
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errXExpected,
errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errXExpectsTwoArguments,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
errInlineIteratorsAsProcParams,
errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
@@ -102,6 +105,10 @@ type
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
errXCannotBeClosure, errXMustBeCompileTime,
errCannotInferTypeOfTheLiteral,
errCannotInferReturnType,
errGenericLambdaNotAllowed,
errCompilerDoesntSupportTarget,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
@@ -112,7 +119,7 @@ type
warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex,
warnUninit, warnUser,
warnUninit, warnGcMem, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
@@ -195,7 +202,7 @@ const
errXExpectsArrayType: "\'$1\' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: "constant division by zero",
errConstantDivisionByZero: "division by zero",
errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: "over- or underflow",
@@ -262,7 +269,7 @@ const
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
errImplOfXexpected: "implementation of \'$1\' expected",
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
errDiscardValue: "value returned by statement has to be discarded",
errDiscardValueX: "value of type '$1' has to be discarded",
errInvalidDiscard: "statement returns no value that can be discarded",
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
@@ -311,6 +318,7 @@ const
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "\'$1\' expected",
errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
@@ -322,6 +330,12 @@ const
errInstantiateXExplicitely: "instantiate '$1' explicitely",
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators",
errXExpectsTwoArguments: "\'$1\' expects two arguments",
errXExpectsObjectTypes: "\'$1\' expects object types",
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
@@ -343,6 +357,12 @@ const
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
errCannotInferReturnType: "cannot infer the return type of the proc",
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
"it is used as an operand to another routine and the types " &
"of the generic paramers can be infered from the expected signature.",
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
@@ -367,6 +387,7 @@ const
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnUser: "$1 [User]",
hintSuccess: "operation successful [Success]",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
@@ -386,7 +407,7 @@ const
hintUser: "$1 [User]"]
const
WarningsToStr*: array[0..23, string] = ["CannotOpenFile", "OctalEscape",
WarningsToStr*: array[0..24, string] = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
@@ -394,7 +415,7 @@ const
"CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "Uninit", "User"]
"ProveInit", "ProveField", "ProveIndex", "Uninit", "GcMem", "User"]
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
@@ -445,7 +466,7 @@ type
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of EInvalidValue
ESuggestDone* = object of EBase
ESuggestDone* = object of E_Base
const
InvalidFileIDX* = int32(-1)
@@ -453,9 +474,9 @@ const
var
filenameToIndexTbl = initTable[string, int32]()
fileInfos*: seq[TFileInfo] = @[]
SystemFileIdx*: int32
systemFileIdx*: int32
proc toCChar*(c: Char): string =
proc toCChar*(c: char): string =
case c
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
of '\'', '\"', '\\': result = '\\' & c
@@ -474,7 +495,7 @@ proc makeCString*(s: string): PRope =
add(res, '\"')
add(res, tnl)
app(result, toRope(res)) # reset:
setlen(res, 1)
setLen(res, 1)
res[0] = '\"'
add(res, toCChar(s[i]))
add(res, '\"')
@@ -545,14 +566,14 @@ var
when useCaas:
var stdoutSocket*: TSocket
proc UnknownLineInfo*(): TLineInfo =
proc unknownLineInfo*(): TLineInfo =
result.line = int16(-1)
result.col = int16(-1)
result.fileIndex = -1
var
msgContext: seq[TLineInfo] = @[]
lastError = UnknownLineInfo()
lastError = unknownLineInfo()
bufferedMsgs*: seq[string]
errorOutputs* = {eStdOut, eStdErr}
@@ -560,20 +581,20 @@ var
proc clearBufferedMsgs* =
bufferedMsgs = nil
proc SuggestWriteln*(s: string) =
proc suggestWriteln*(s: string) =
if eStdOut in errorOutputs:
when useCaas:
if isNil(stdoutSocket): Writeln(stdout, s)
if isNil(stdoutSocket): writeln(stdout, s)
else:
Writeln(stdout, s)
writeln(stdout, s)
stdoutSocket.send(s & "\c\L")
else:
Writeln(stdout, s)
writeln(stdout, s)
if eInMemory in errorOutputs:
bufferedMsgs.safeAdd(s)
proc SuggestQuit*() =
proc suggestQuit*() =
if not isServing:
quit(0)
elif isWorkingWithDirtyBuffer:
@@ -601,12 +622,12 @@ proc pushInfoContext*(info: TLineInfo) =
msgContext.add(info)
proc popInfoContext*() =
setlen(msgContext, len(msgContext) - 1)
setLen(msgContext, len(msgContext) - 1)
proc getInfoContext*(index: int): TLineInfo =
let L = msgContext.len
let i = if index < 0: L + index else: index
if i >=% L: result = UnknownLineInfo()
if i >=% L: result = unknownLineInfo()
else: result = msgContext[i]
proc toFilename*(fileIdx: int32): string =
@@ -643,6 +664,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
proc toFileLineCol*(info: TLineInfo): string {.inline.} =
result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
template `$`*(info: TLineInfo): expr = toFileLineCol(info)
proc `??`* (info: TLineInfo, filename: string): bool =
# only for debugging purposes
result = filename in info.toFilename
@@ -656,18 +679,18 @@ proc addCheckpoint*(info: TLineInfo) =
proc addCheckpoint*(filename: string, line: int) =
addCheckpoint(newLineInfo(filename, line, - 1))
proc OutWriteln*(s: string) =
proc outWriteln*(s: string) =
## Writes to stdout. Always.
if eStdOut in errorOutputs: Writeln(stdout, s)
if eStdOut in errorOutputs: writeln(stdout, s)
proc MsgWriteln*(s: string) =
proc msgWriteln*(s: string) =
## Writes to stdout. If --stdout option is given, writes to stderr instead.
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if optStdout in gGlobalOptions:
if eStdErr in errorOutputs: Writeln(stderr, s)
if eStdErr in errorOutputs: writeln(stderr, s)
else:
if eStdOut in errorOutputs: Writeln(stdout, s)
if eStdOut in errorOutputs: writeln(stdout, s)
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
@@ -675,9 +698,9 @@ proc coordToStr(coord: int): string =
if coord == -1: result = "???"
else: result = $coord
proc MsgKindToString*(kind: TMsgKind): string =
proc msgKindToString*(kind: TMsgKind): string =
# later versions may provide translated error messages
result = msgKindToStr[kind]
result = MsgKindToStr[kind]
proc getMessageStr(msg: TMsgKind, arg: string): string =
result = msgKindToString(msg) % [arg]
@@ -699,58 +722,55 @@ type
TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace =
if defined(debug) or gVerbosity >= 3:
template quit =
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
writeStackTrace()
quit 1
if msg == errInternal:
writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax:
maybeTrace()
quit(1)
if msg >= errMin and msg <= errMax:
maybeTrace()
if msg >= fatalMin and msg <= fatalMax:
quit()
if msg >= errMin and msg <= errMax:
inc(gErrorCounter)
options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax:
quit(1)
if gErrorCounter >= gErrorMax:
quit()
elif eh == doAbort and gCmd != cmdIdeTools:
quit(1)
quit()
elif eh == doRaise:
raiseRecoverableError(s)
proc `==`*(a, b: TLineInfo): bool =
proc `==`*(a, b: TLineInfo): bool =
result = a.line == b.line and a.fileIndex == b.fileIndex
proc writeContext(lastinfo: TLineInfo) =
var info = lastInfo
var info = lastinfo
for i in countup(0, len(msgContext) - 1):
if msgContext[i] != lastInfo and msgContext[i] != info:
MsgWriteln(posContextFormat % [toMsgFilename(msgContext[i]),
if msgContext[i] != lastinfo and msgContext[i] != info:
msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
coordToStr(msgContext[i].line),
coordToStr(msgContext[i].col),
getMessageStr(errInstantiationFrom, "")])
info = msgContext[i]
proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
var frmt: string
case msg
of errMin..errMax:
writeContext(unknownLineInfo())
frmt = rawErrorFormat
frmt = RawErrorFormat
of warnMin..warnMax:
if optWarns notin gOptions: return
if msg notin gNotes: return
writeContext(unknownLineInfo())
frmt = rawWarningFormat
frmt = RawWarningFormat
inc(gWarnCounter)
of hintMin..hintMax:
if optHints notin gOptions: return
if msg notin gNotes: return
frmt = rawHintFormat
frmt = RawHintFormat
inc(gHintCounter)
let s = `%`(frmt, `%`(msgKindToString(msg), args))
MsgWriteln(s)
msgWriteln(s)
handleError(msg, doAbort, s)
proc rawMessage*(msg: TMsgKind, arg: string) =
@@ -758,8 +778,8 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
proc writeSurroundingSrc(info: TLineInfo) =
const indent = " "
MsgWriteln(indent & info.sourceLine.ropeToStr)
MsgWriteln(indent & repeatChar(info.col, ' ') & '^')
msgWriteln(indent & info.sourceLine.ropeToStr)
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
@@ -768,7 +788,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
case msg
of errMin..errMax:
writeContext(info)
frmt = posErrorFormat
frmt = PosErrorFormat
# we try to filter error messages so that not two error message
# in the same file and line are produced:
#ignoreMsg = lastError == info and eh != doAbort
@@ -776,54 +796,54 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
of warnMin..warnMax:
ignoreMsg = optWarns notin gOptions or msg notin gNotes
if not ignoreMsg: writeContext(info)
frmt = posWarningFormat
frmt = PosWarningFormat
inc(gWarnCounter)
of hintMin..hintMax:
ignoreMsg = optHints notin gOptions or msg notin gNotes
frmt = posHintFormat
frmt = PosHintFormat
inc(gHintCounter)
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
coordToStr(info.col), getMessageStr(msg, arg)]
if not ignoreMsg:
MsgWriteln(s)
msgWriteln(s)
if optPrintSurroundingSrc and msg in errMin..errMax:
info.writeSurroundingSrc
handleError(msg, eh, s)
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doAbort)
proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doRaise)
proc GlobalError*(info: TLineInfo, arg: string) =
proc globalError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doRaise)
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc LocalError*(info: TLineInfo, arg: string) =
proc localError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doNothing)
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc InternalError*(info: TLineInfo, errMsg: string) =
proc internalError*(info: TLineInfo, errMsg: string) =
if gCmd == cmdIdeTools: return
writeContext(info)
liMessage(info, errInternal, errMsg, doAbort)
proc InternalError*(errMsg: string) =
proc internalError*(errMsg: string) =
if gCmd == cmdIdeTools: return
writeContext(UnknownLineInfo())
writeContext(unknownLineInfo())
rawMessage(errInternal, errMsg)
template AssertNotNil*(e: expr): expr =
if e == nil: InternalError($InstantiationInfo())
template assertNotNil*(e: expr): expr =
if e == nil: internalError($instantiationInfo())
e
template InternalAssert*(e: bool): stmt =
if not e: InternalError($InstantiationInfo())
template internalAssert*(e: bool): stmt =
if not e: internalError($instantiationInfo())
proc addSourceLine*(fileIdx: int32, line: string) =
fileInfos[fileIdx].lines.add line.toRope
@@ -837,23 +857,22 @@ proc sourceLine*(i: TLineInfo): PRope =
addSourceLine i.fileIndex, line.string
except EIO:
discard
InternalAssert i.fileIndex < fileInfos.len
internalAssert i.fileIndex < fileInfos.len
# can happen if the error points to EOF:
if i.line > fileInfos[i.fileIndex].lines.len: return nil
result = fileInfos[i.fileIndex].lines[i.line-1]
proc quotedFilename*(i: TLineInfo): PRope =
InternalAssert i.fileIndex >= 0
internalAssert i.fileIndex >= 0
result = fileInfos[i.fileIndex].quotedName
ropes.ErrorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
case err
of rInvalidFormatStr:
internalError("ropes: invalid format string: " & msg)
of rTokenTooLong:
internalError("ropes: token too long: " & msg)
of rCannotOpenFile:
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
msg)
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)

View File

@@ -49,7 +49,7 @@ proc parseExpr(L: var TLexer, tok: var TToken): bool =
var b = parseAndExpr(L, tok)
result = result or b
proc EvalppIf(L: var TLexer, tok: var TToken): bool =
proc evalppIf(L: var TLexer, tok: var TToken): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
@@ -60,7 +60,7 @@ var condStack: seq[bool] = @[]
proc doEnd(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
ppGetTok(L, tok) # skip 'end'
setlen(condStack, high(condStack))
setLen(condStack, high(condStack))
type
TJumpDest = enum
@@ -75,18 +75,18 @@ proc doElse(L: var TLexer, tok: var TToken) =
proc doElif(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
var res = EvalppIf(L, tok)
var res = evalppIf(L, tok)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
else: condStack[high(condStack)] = true
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
var nestedIfs = 0
while True:
while true:
if (tok.ident != nil) and (tok.ident.s == "@"):
ppGetTok(L, tok)
case whichKeyword(tok.ident)
of wIf:
Inc(nestedIfs)
inc(nestedIfs)
of wElse:
if (dest == jdElseEndif) and (nestedIfs == 0):
doElse(L, tok)
@@ -99,21 +99,21 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
if nestedIfs == 0:
doEnd(L, tok)
break
if nestedIfs > 0: Dec(nestedIfs)
if nestedIfs > 0: dec(nestedIfs)
else:
nil
discard
ppGetTok(L, tok)
elif tok.tokType == tkEof:
elif tok.tokType == tkEof:
lexMessage(L, errTokenExpected, "@end")
else:
else:
ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
setlen(condStack, len(condStack) + 1)
var res = EvalppIf(L, tok)
setLen(condStack, len(condStack) + 1)
var res = evalppIf(L, tok)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok)
@@ -121,7 +121,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
of wEnd: doEnd(L, tok)
of wWrite:
ppGetTok(L, tok)
msgs.MsgWriteln(tokToStr(tok))
msgs.msgWriteln(tokToStr(tok))
ppGetTok(L, tok)
else:
case tok.ident.s.normalize
@@ -135,13 +135,13 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, tokToStr(tok) & os.getenv(key))
os.putEnv(key, tokToStr(tok) & os.getEnv(key))
ppGetTok(L, tok)
of "appendenv":
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, os.getenv(key) & tokToStr(tok))
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
@@ -196,7 +196,7 @@ proc readConfigFile(filename: string) =
L: TLexer
tok: TToken
stream: PLLStream
stream = LLStreamOpen(filename, fmRead)
stream = llStreamOpen(filename, fmRead)
if stream != nil:
initToken(tok)
openLexer(L, filename, stream)
@@ -219,7 +219,7 @@ proc getSystemConfigPath(filename: string): string =
if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename
proc LoadConfigs*(cfg: string) =
proc loadConfigs*(cfg: string) =
# set default value (can be overwritten):
if libpath == "":
# choose default libpath:

View File

@@ -17,11 +17,11 @@ proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
LoadConfigs(DefaultConfig)
loadConfigs(DefaultConfig)
initDefines()
DefineSymbol("nimrodvm")
when hasFFI: DefineSymbol("nimffi")
defineSymbol("nimrodvm")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(vmPass)
@@ -30,4 +30,4 @@ proc execute*(program: string) =
compileSystemModule()
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, LLStreamOpen(program), nil)
processModule(m, llStreamOpen(program), nil)

View File

@@ -42,7 +42,7 @@ type
buf*: cstring
bufLen*: int # length of buffer in characters
stream*: PLLStream # we read from this stream
LineNumber*: int # the current line number
lineNumber*: int # the current line number
# private data:
sentinel*: int
lineStart*: int # index of last line start in buffer
@@ -54,11 +54,11 @@ proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
proc closeBaseLexer*(L: var TBaseLexer)
proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
proc getColNumber*(L: TBaseLexer, pos: int): int
proc HandleCR*(L: var TBaseLexer, pos: int): int
proc handleCR*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over CR in the buffer; it returns the
# position to continue the scanning from. `pos` must be the position
# of the CR.
proc HandleLF*(L: var TBaseLexer, pos: int): int
proc handleLF*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over LF in the buffer; it returns the the
# position to continue the scanning from. `pos` must be the position
# of the LF.
@@ -69,9 +69,9 @@ const
proc closeBaseLexer(L: var TBaseLexer) =
dealloc(L.buf)
LLStreamClose(L.stream)
llStreamClose(L.stream)
proc FillBuffer(L: var TBaseLexer) =
proc fillBuffer(L: var TBaseLexer) =
var
charsRead, toCopy, s: int # all are in characters,
# not bytes (in case this
@@ -80,12 +80,12 @@ proc FillBuffer(L: var TBaseLexer) =
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.BufLen - L.sentinel - 1
toCopy = L.bufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
# "moveMem" handles overlapping regions
charsRead = LLStreamRead(L.stream, addr(L.buf[toCopy]),
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
(L.sentinel + 1) * chrSize) div chrSize
s = toCopy + charsRead
if charsRead < L.sentinel + 1:
@@ -96,7 +96,7 @@ proc FillBuffer(L: var TBaseLexer) =
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
L.sentinel = s
@@ -104,11 +104,11 @@ proc FillBuffer(L: var TBaseLexer) =
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.BufLen
L.bufLen = L.BufLen * 2
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
assert(L.bufLen - oldBuflen == oldBufLen)
charsRead = LLStreamRead(L.stream, addr(L.buf[oldBufLen]),
assert(L.bufLen - oldBufLen == oldBufLen)
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
oldBufLen * chrSize) div chrSize
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
@@ -126,20 +126,20 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
result = 0
L.lineStart = result
proc HandleCR(L: var TBaseLexer, pos: int): int =
proc handleCR(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == CR)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos)
if L.buf[result] == LF:
result = fillBaseLexer(L, result)
proc HandleLF(L: var TBaseLexer, pos: int): int =
proc handleLF(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == LF)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
proc skip_UTF_8_BOM(L: var TBaseLexer) =
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
proc skipUTF8BOM(L: var TBaseLexer) =
if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF':
inc(L.bufpos, 3)
inc(L.lineStart, 3)
@@ -150,10 +150,10 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
L.buf = cast[cstring](alloc(bufLen * chrSize))
L.sentinel = bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.lineNumber = 1 # lines start at 1
L.stream = inputstream
fillBuffer(L)
skip_UTF_8_BOM(L)
skipUTF8BOM(L)
proc getColNumber(L: TBaseLexer, pos: int): int =
result = abs(pos - L.lineStart)
@@ -166,5 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
inc(i)
result.add("\n")
if marker:
result.add(RepeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")

View File

@@ -31,12 +31,12 @@ proc prependCurDir(f: string): string =
else:
result = f
proc HandleCmdLine() =
proc handleCmdLine() =
if paramCount() == 0:
writeCommandLineUsage()
else:
# Process command line arguments:
ProcessCmdLine(passCmd1, "")
processCmdLine(passCmd1, "")
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
@@ -47,12 +47,12 @@ proc HandleCmdLine() =
gProjectName = p.name
else:
gProjectPath = getCurrentDir()
LoadConfigs(DefaultConfig) # load all config files
loadConfigs(DefaultConfig) # load all config files
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
ProcessCmdLine(passCmd2, "")
MainCommand()
processCmdLine(passCmd2, "")
mainCommand()
if gVerbosity >= 2: echo(GC_getStatistics())
#echo(GC_getStatistics())
if msgs.gErrorCounter == 0:
@@ -71,7 +71,7 @@ proc HandleCmdLine() =
binPath = options.outFile.prependCurDir
else:
# Figure out ourselves a valid binary name.
binPath = changeFileExt(gProjectFull, exeExt).prependCurDir
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(ex & ' ' & service.arguments)
@@ -81,8 +81,8 @@ when defined(GC_setMaxPause):
when compileOption("gc", "v2") or compileOption("gc", "refc"):
# the new correct mark&sweet collector is too slow :-/
GC_disableMarkAndSweep()
condsyms.InitDefines()
condsyms.initDefines()
when not defined(selftest):
HandleCmdLine()
handleCmdLine()
quit(int8(msgs.gErrorCounter > 0))

View File

@@ -13,3 +13,11 @@ path:"$lib/packages/docutils"
define:booting
import:testability
@if windows:
cincludes: "$lib/wrappers/libffi/common"
@end
define:useStdoutAsStdmsg
cs:partial
#define:useNodeIds

View File

@@ -18,7 +18,7 @@ proc overlap*(a, b: PNode): bool
proc inSet*(s: PNode, elem: PNode): bool
proc someInSet*(s: PNode, a, b: PNode): bool
proc emptyRange*(a, b: PNode): bool
proc SetHasRange*(s: PNode): bool
proc setHasRange*(s: PNode): bool
# returns true if set contains a range (needed by the code generator)
# these are used for constant folding:
proc unionSets*(a, b: PNode): PNode
@@ -32,7 +32,7 @@ proc cardSet*(s: PNode): BiggestInt
proc inSet(s: PNode, elem: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "inSet")
internalError(s.info, "inSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -58,10 +58,10 @@ proc overlap(a, b: PNode): bool =
else:
result = sameValue(a, b)
proc SomeInSet(s: PNode, a, b: PNode): bool =
proc someInSet(s: PNode, a, b: PNode): bool =
# checks if some element of a..b is in the set s
if s.kind != nkCurly:
InternalError(s.info, "SomeInSet")
internalError(s.info, "SomeInSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -82,12 +82,12 @@ proc toBitSet(s: PNode, b: var TBitSet) =
if s.sons[i].kind == nkRange:
j = getOrdValue(s.sons[i].sons[0])
while j <= getOrdValue(s.sons[i].sons[1]):
BitSetIncl(b, j - first)
bitSetIncl(b, j - first)
inc(j)
else:
BitSetIncl(b, getOrdValue(s.sons[i]) - first)
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType
@@ -98,14 +98,14 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
result.typ = settype
result.info = info
e = 0
while e < len(s) * elemSize:
while e < len(s) * ElemSize:
if bitSetIn(s, e):
a = e
b = e
while true:
Inc(b)
if (b >= len(s) * elemSize) or not bitSetIn(s, b): break
Dec(b)
inc(b)
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
dec(b)
if a == b:
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
else:
@@ -115,7 +115,7 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
addSon(n, newIntTypeNode(nkIntLit, b + first, elemType))
addSon(result, n)
e = b
Inc(e)
inc(e)
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
var x, y: TBitSet
@@ -124,10 +124,10 @@ template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
op(x, y)
result = toTreeSet(x, a.typ, a.info)
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetUnion)
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetDiff)
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetIntersect)
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetSymDiff)
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc containsSets(a, b: PNode): bool =
var x, y: TBitSet
@@ -156,11 +156,11 @@ proc cardSet(s: PNode): BiggestInt =
result = result + getOrdValue(s.sons[i].sons[1]) -
getOrdValue(s.sons[i].sons[0]) + 1
else:
Inc(result)
inc(result)
proc SetHasRange(s: PNode): bool =
proc setHasRange(s: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "SetHasRange")
internalError(s.info, "SetHasRange")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:

View File

@@ -100,6 +100,8 @@ var
gSelectedGC* = gcRefc # the selected GC
searchPaths*, lazyPaths*: TLinkedList
outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
@@ -143,7 +145,7 @@ const
# additional configuration variables:
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringtable(modeCaseInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive)
libpath* = ""
gProjectName* = "" # holds a name like 'nimrod'
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
@@ -159,8 +161,6 @@ var
const oKeepVariableNames* = true
const oUseLateInstantiation* = false
proc mainCommandArg*: string =
## This is intended for commands like check or parse
## which will work on the main project file unless
@@ -185,7 +185,7 @@ proc getOutFile*(filename, ext: string): string =
proc getPrefixDir*(): string =
## gets the application directory
result = SplitPath(getAppDir()).head
result = splitPath(getAppDir()).head
proc canonicalizePath*(path: string): string =
result = path.expandFilename
@@ -193,16 +193,16 @@ proc canonicalizePath*(path: string): string =
proc shortenDir*(dir: string): string =
## returns the interesting part of a dir
var prefix = getPrefixDir() & dirSep
var prefix = getPrefixDir() & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
prefix = gProjectPath & dirSep
prefix = gProjectPath & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
result = dir
proc removeTrailingDirSep*(path: string): string =
if (len(path) > 0) and (path[len(path) - 1] == dirSep):
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
result = substr(path, 0, len(path) - 2)
else:
result = path
@@ -211,21 +211,42 @@ proc getGeneratedPath: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
template newPackageCache(): expr =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache()
proc resetPackageCache*() = packageCache = newPackageCache()
iterator myParentDirs(p: string): string =
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
var current = p
while true:
current = current.parentDir
if current.len == 0: break
yield current
proc getPackageName*(path: string): string =
var q = 1
var b = 0
if path[len(path)-1] in {dirsep, altsep}: q = 2
for i in countdown(len(path)-q, 0):
if path[i] in {dirsep, altsep}:
if b == 0: b = i
else:
let x = path.substr(i+1, b-1)
case x.normalize
of "lib", "src", "source", "package", "pckg", "library", "private":
b = i
else:
return x.replace('.', '_')
result = ""
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
# we also store if we didn't find anything:
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
dec parents
if parents <= 0: break
proc withPackageName*(path: string): string =
let x = path.getPackageName
@@ -255,15 +276,15 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result
iterator iterSearchPath*(SearchPaths: TLinkedList): string =
var it = PStrEntry(SearchPaths.head)
iterator iterSearchPath*(searchPaths: TLinkedList): string =
var it = PStrEntry(searchPaths.head)
while it != nil:
yield it.data
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
proc rawFindFile(f: string): string =
for it in iterSearchPath(SearchPaths):
result = JoinPath(it, f)
for it in iterSearchPath(searchPaths):
result = joinPath(it, f)
if existsFile(result):
return result.canonicalizePath
result = ""
@@ -271,14 +292,14 @@ proc rawFindFile(f: string): string =
proc rawFindFile2(f: string): string =
var it = PStrEntry(lazyPaths.head)
while it != nil:
result = JoinPath(it.data, f)
result = joinPath(it.data, f)
if existsFile(result):
bringToFront(lazyPaths, it)
return result.canonicalizePath
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
result = ""
proc FindFile*(f: string): string {.procvar.} =
proc findFile*(f: string): string {.procvar.} =
result = f.rawFindFile
if result.len == 0:
result = f.toLower.rawFindFile
@@ -289,11 +310,11 @@ proc FindFile*(f: string): string {.procvar.} =
proc findModule*(modulename, currentModule: string): string =
# returns path to module
let m = addFileExt(modulename, nimExt)
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = FindFile(m)
result = findFile(m)
proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(')
@@ -320,7 +341,7 @@ proc inclDynlibOverride*(lib: string) =
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 b = len(x) - 1
while a <= b:

View File

@@ -42,7 +42,7 @@ const
MaxStackSize* = 64 ## max required stack size by the VM
proc patternError(n: PNode) =
LocalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
add(code, chr(ord(op)))
@@ -97,14 +97,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
of "nosideeffect": result.add(ppNoSideEffect)
else:
# check all symkinds:
InternalAssert int(high(TSymKind)) < 255
internalAssert int(high(TSymKind)) < 255
for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind)
result.add(chr(i.ord))
return
# check all nodekinds:
InternalAssert int(high(TNodeKind)) < 255
internalAssert int(high(TNodeKind)) < 255
for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
@@ -124,8 +124,8 @@ proc semNodeKindConstraints*(p: PNode): PNode =
if p.len >= 2:
for i in 1.. <p.len:
compileConstraints(p.sons[i], result.strVal)
if result.strVal.len > maxStackSize-1:
InternalError(p.info, "parameter pattern too complex")
if result.strVal.len > MaxStackSize-1:
internalError(p.info, "parameter pattern too complex")
else:
patternError(p)
result.strVal.add(ppEof)
@@ -216,12 +216,12 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n.sons[0])
else:
nil
discard
proc matchNodeKinds*(p, n: PNode): bool =
# matches the parameter constraint 'p' against the concrete AST 'n'.
# Efficiency matters here.
var stack {.noinit.}: array[0..maxStackSize, bool]
var stack {.noinit.}: array[0..MaxStackSize, bool]
# empty patterns are true:
stack[0] = true
var sp = 1

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -18,10 +18,10 @@
# In fact the grammar is generated from this file:
when isMainModule:
import pegs
var outp = open("compiler/grammar.txt", fmWrite)
var outp = open("doc/grammar.txt", fmWrite)
for line in lines("compiler/parser.nim"):
if line =~ peg" \s* '#| ' {.*}":
outp.writeln matches[0]
outp.write matches[0], "\L"
outp.close
import
@@ -31,12 +31,13 @@ type
TParser*{.final.} = object # a TParser object represents a module that
# is being parsed
currInd: int # current indentation
firstTok: bool
firstTok, strongSpaces: bool
lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token
inPragma: int
inSemiStmtList: int
proc ParseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
proc parseAll*(p: var TParser): PNode
proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode
# implements an iterator. Returns the next top-level statement or
@@ -48,7 +49,6 @@ proc parseString*(s: string, filename: string = "", line: int = 0): PNode
# correct error messages referring to the original source.
# helpers for the other parsers
proc getPrecedence*(tok: TToken): int
proc isOperator*(tok: TToken): bool
proc getTok*(p: var TParser)
proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "")
@@ -59,15 +59,15 @@ proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode
proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode
proc newIdentNodeP*(ident: PIdent, p: TParser): PNode
proc expectIdentOrKeyw*(p: TParser)
proc ExpectIdent*(p: TParser)
proc expectIdent*(p: TParser)
proc parLineInfo*(p: TParser): TLineInfo
proc Eat*(p: var TParser, TokType: TTokType)
proc eat*(p: var TParser, tokType: TTokType)
proc skipInd*(p: var TParser)
proc optPar*(p: var TParser)
proc optInd*(p: var TParser, n: PNode)
proc indAndComment*(p: var TParser, n: PNode)
proc setBaseFlags*(n: PNode, base: TNumericalBase)
proc parseSymbol*(p: var TParser): PNode
proc parseSymbol*(p: var TParser, allowNil = false): PNode
proc parseTry(p: var TParser): PNode
proc parseCase(p: var TParser): PNode
# implementation
@@ -75,17 +75,20 @@ proc parseCase(p: var TParser): PNode
proc getTok(p: var TParser) =
rawGetTok(p.lex, p.tok)
proc OpenParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream) =
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
strongSpaces=false) =
initToken(p.tok)
OpenLexer(p.lex, fileIdx, inputstream)
openLexer(p.lex, fileIdx, inputStream)
getTok(p) # read the first token
p.firstTok = true
p.strongSpaces = strongSpaces
proc OpenParser*(p: var TParser, filename: string, inputStream: PLLStream) =
openParser(p, filename.fileInfoIdx, inputStream)
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
strongSpaces=false) =
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
proc CloseParser(p: var TParser) =
CloseLexer(p.lex)
proc closeParser(p: var TParser) =
closeLexer(p.lex)
proc parMessage(p: TParser, msg: TMsgKind, arg: string = "") =
lexMessage(p.lex, msg, arg)
@@ -135,12 +138,12 @@ proc expectIdentOrKeyw(p: TParser) =
if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
proc ExpectIdent(p: TParser) =
proc expectIdent(p: TParser) =
if p.tok.tokType != tkSymbol:
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
proc Eat(p: var TParser, TokType: TTokType) =
if p.tok.TokType == TokType: getTok(p)
proc eat(p: var TParser, tokType: TTokType) =
if p.tok.tokType == tokType: getTok(p)
else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
proc parLineInfo(p: TParser): TLineInfo =
@@ -185,40 +188,58 @@ proc relevantOprChar(ident: PIdent): char {.inline.} =
if result == '\\' and L > 1:
result = ident.s[1]
proc IsSigilLike(tok: TToken): bool {.inline.} =
proc isSigilLike(tok: TToken): bool {.inline.} =
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
proc IsLeftAssociative(tok: TToken): bool {.inline.} =
proc isLeftAssociative(tok: TToken): bool {.inline.} =
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
proc getPrecedence(tok: TToken): int =
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
template considerStrongSpaces(x): expr =
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType
of tkOpr:
let L = tok.ident.s.len
let relevantChar = relevantOprChar(tok.ident)
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: value
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
case relevantChar
of '$', '^': considerAsgn(10)
of '*', '%', '/', '\\': considerAsgn(9)
of '~': result = 8
of '~': result = considerStrongSpaces(8)
of '+', '-', '|': considerAsgn(8)
of '&': considerAsgn(7)
of '=', '<', '>', '!': result = 5
of '=', '<', '>', '!': result = considerStrongSpaces(5)
of '.': considerAsgn(6)
of '?': result = 2
of '?': result = considerStrongSpaces(2)
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = 6
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = considerStrongSpaces(6)
of tkAnd: result = 4
of tkOr, tkXor: result = 3
else: result = - 10
proc isOperator(tok: TToken): bool =
result = getPrecedence(tok) >= 0
else: result = -10
proc isOperator(tok: TToken): bool =
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
proc isUnary(p: TParser): bool =
p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
p.tok.strongSpaceB == 0 and
p.tok.strongSpaceA > 0
proc checkBinary(p: TParser) {.inline.} =
# we don't check '..' here as that's too annoying
if p.strongSpaces and p.tok.tokType == tkOpr:
if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
parMessage(p, errGenerated, "number of spaces around '$#' not consistent"%
prettyTok(p.tok))
elif p.tok.strongSpaceA notin {0,1,2,4,8}:
parMessage(p, errGenerated, "number of spaces must be 0,1,2,4 or 8")
#| module = stmt ^* (';' / IND{=})
#|
@@ -252,7 +273,7 @@ proc colcom(p: var TParser, n: PNode) =
eat(p, tkColon)
skipComment(p, n)
proc parseSymbol(p: var TParser): PNode =
proc parseSymbol(p: var TParser, allowNil = false): PNode =
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
#| | IDENT
case p.tok.tokType
@@ -279,7 +300,7 @@ proc parseSymbol(p: var TParser): PNode =
add(result, newIdentNodeP(getIdent"{}", p))
getTok(p)
eat(p, tkCurlyRi)
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot:
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
add(result, newIdentNodeP(p.tok.ident, p))
getTok(p)
of tkIntLit..tkCharLit:
@@ -291,9 +312,13 @@ proc parseSymbol(p: var TParser): PNode =
break
eat(p, tkAccent)
else:
parMessage(p, errIdentifierExpected, p.tok)
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
result = ast.emptyNode
if allowNil and p.tok.tokType == tkNil:
result = newNodeP(nkNilLit, p)
getTok(p)
else:
parMessage(p, errIdentifierExpected, p.tok)
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
result = ast.emptyNode
proc indexExpr(p: var TParser): PNode =
#| indexExpr = expr
@@ -427,7 +452,7 @@ proc parseCast(p: var TParser): PNode =
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@@ -454,11 +479,13 @@ proc complexOrSimpleStmt(p: var TParser): PNode
proc simpleExpr(p: var TParser, mode = pmNormal): PNode
proc semiStmtList(p: var TParser, result: PNode) =
inc p.inSemiStmtList
result.add(complexOrSimpleStmt(p))
while p.tok.tokType == tkSemicolon:
while p.tok.tokType == tkSemiColon:
getTok(p)
optInd(p, result)
result.add(complexOrSimpleStmt(p))
dec p.inSemiStmtList
result.kind = nkStmtListExpr
proc parsePar(p: var TParser): PNode =
@@ -482,7 +509,7 @@ proc parsePar(p: var TParser): PNode =
# XXX 'bind' used to be an expression, so we exclude it here;
# tests/reject/tbind2 fails otherwise.
semiStmtList(p, result)
elif p.tok.tokType == tkSemicolon:
elif p.tok.tokType == tkSemiColon:
# '(;' enforces 'stmt' context:
getTok(p)
optInd(p, result)
@@ -498,7 +525,9 @@ proc parsePar(p: var TParser): PNode =
asgn.sons[0] = a
asgn.sons[1] = b
result.add(asgn)
elif p.tok.tokType == tkSemicolon:
if p.tok.tokType == tkSemiColon:
semiStmtList(p, result)
elif p.tok.tokType == tkSemiColon:
# stmt context:
result.add(a)
semiStmtList(p, result)
@@ -518,14 +547,14 @@ proc parsePar(p: var TParser): PNode =
eat(p, tkParRi)
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
#| identOrLiteral = generalizedLit | symbol
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| identOrLiteral = generalizedLit | symbol | literal
#| | par | arrayConstr | setOrTableConstr
#| | castExpr
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -634,16 +663,20 @@ proc namedParams(p: var TParser, callee: PNode,
addSon(result, a)
exprColonEqExprListAux(p, endTok, result)
proc primarySuffix(p: var TParser, r: PNode): PNode =
proc parseMacroColon(p: var TParser, x: PNode): PNode
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
#| | '[' optInd indexExprList optPar ']'
#| | '{' optInd indexExprList optPar '}'
#| | &( '`'|IDENT|literal|'cast') expr # command syntax
result = r
while p.tok.indent < 0:
while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
case p.tok.tokType
of tkParLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
@@ -658,21 +691,47 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
result = dotExpr(p, result)
result = parseGStrLit(p, result)
of tkBracketLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
else: break
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
if p.inPragma == 0:
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
# solution, but pragmas.nim can't handle that
let a = result
result = newNodeP(nkCommand, p)
addSon(result, a)
addSon result, parseExpr(p)
when false:
while p.tok.tokType != tkEof:
let a = parseExpr(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
else:
result = parseMacroColon(p, result)
break
else:
break
proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = primary(p, mode)
proc parseOperators(p: var TParser, headNode: PNode,
limit: int, mode: TPrimaryMode): PNode =
result = headNode
# expand while operators have priorities higher than 'limit'
var opPrec = getPrecedence(p.tok)
var opPrec = getPrecedence(p.tok, p.strongSpaces)
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
# the operator itself must not start on a new line:
while opPrec >= limit and p.tok.indent < 0:
var leftAssoc = ord(IsLeftAssociative(p.tok))
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
checkBinary(p)
var leftAssoc = ord(isLeftAssociative(p.tok))
var a = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
getTok(p)
@@ -683,7 +742,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
addSon(a, result)
addSon(a, b)
result = a
opPrec = getPrecedence(p.tok)
opPrec = getPrecedence(p.tok, p.strongSpaces)
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = primary(p, mode)
result = parseOperators(p, result, limit, mode)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
result = simpleExprAux(p, -1, mode)
@@ -713,6 +776,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
proc parsePragma(p: var TParser): PNode =
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
result = newNodeP(nkPragma, p)
inc p.inPragma
getTok(p)
optInd(p, result)
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
@@ -724,6 +788,7 @@ proc parsePragma(p: var TParser): PNode =
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
else: parMessage(p, errTokenExpected, ".}")
dec p.inPragma
proc identVis(p: var TParser): PNode =
#| identVis = symbol opr? # postfix position
@@ -798,7 +863,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseIdentColonEquals(p, {})
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
@@ -840,13 +905,13 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
parMessage(p, errTokenExpected, ")")
break
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
eat(p, tkParRi)
let hasRet = if retColon: p.tok.tokType == tkColon
else: p.tok.tokType == tkOpr and IdentEq(p.tok.ident, "->")
else: p.tok.tokType == tkOpr and identEq(p.tok.ident, "->")
if hasRet and p.tok.indent < 0:
getTok(p)
optInd(p, result)
@@ -905,14 +970,30 @@ proc isExprStart(p: TParser): bool =
tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared:
result = true
else: result = false
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
mode: TPrimaryMode): PNode =
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
while true:
var s = parseSymbol(p, allowNil)
if s.kind == nkEmpty: break
addSon(result, s)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, s)
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
mode: TPrimaryMode): PNode =
result = newNodeP(kind, p)
getTok(p)
optInd(p, result)
if not isOperator(p.tok) and isExprStart(p):
addSon(result, primary(p, mode))
if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
let nodeKind = if p.tok.tokType == tkWith: nkWith
else: nkWithout
getTok(p)
let list = newNodeP(nodeKind, p)
result.addSon list
parseSymbolList(p, list, allowNil = true)
proc parseExpr(p: var TParser): PNode =
#| expr = (ifExpr
@@ -929,7 +1010,6 @@ proc parseExpr(p: var TParser): PNode =
proc parseEnum(p: var TParser): PNode
proc parseObject(p: var TParser): PNode
proc parseDistinct(p: var TParser): PNode
proc parseTypeClass(p: var TParser): PNode
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
@@ -941,7 +1021,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
#| / 'static' primary
#| / 'bind' primary
if isOperator(p.tok):
let isSigil = IsSigilLike(p.tok)
let isSigil = isSigilLike(p.tok)
result = newNodeP(nkPrefix, p)
var a = newIdentNodeP(p.tok.ident, p)
addSon(result, a)
@@ -949,8 +1029,9 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
optInd(p, a)
if isSigil:
#XXX prefix operators
let baseInd = p.lex.currLineIndent
addSon(result, primary(p, pmSkipSuffix))
result = primarySuffix(p, result)
result = primarySuffix(p, result, baseInd)
else:
addSon(result, primary(p, pmNormal))
return
@@ -965,14 +1046,19 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
of tkIterator:
if mode in {pmTypeDesc, pmTypeDef}:
result = parseProcExpr(p, false)
result.kind = nkIteratorTy
when false:
if mode in {pmTypeDesc, pmTypeDef}:
result = parseProcExpr(p, false)
result.kind = nkIteratorTy
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
if result.kind == nkLambda: result.kind = nkIteratorDef
else: result.kind = nkIteratorTy
of tkEnum:
if mode == pmTypeDef:
result = parseEnum(p)
@@ -995,18 +1081,23 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
getTokNoInd(p)
addSon(result, primary(p, pmNormal))
of tkStatic:
result = newNodeP(nkStaticExpr, p)
let info = parLineInfo(p)
getTokNoInd(p)
addSon(result, primary(p, pmNormal))
let next = primary(p, pmNormal)
if next.kind == nkBracket and next.sonsLen == 1:
result = newNode(nkStaticTy, info, @[next.sons[0]])
else:
result = newNode(nkStaticExpr, info, @[next])
of tkBind:
result = newNodeP(nkBind, p)
getTok(p)
optInd(p, result)
addSon(result, primary(p, pmNormal))
else:
let baseInd = p.lex.currLineIndent
result = identOrLiteral(p, mode)
if mode != pmSkipSuffix:
result = primarySuffix(p, result)
result = primarySuffix(p, result, baseInd)
proc parseTypeDesc(p: var TParser): PNode =
#| typeDesc = simpleExpr
@@ -1014,6 +1105,7 @@ proc parseTypeDesc(p: var TParser): PNode =
proc parseTypeDefAux(p: var TParser): PNode =
#| typeDefAux = simpleExpr
#| | 'generic' typeClass
result = simpleExpr(p, pmTypeDef)
proc makeCall(n: PNode): PNode =
@@ -1023,17 +1115,54 @@ proc makeCall(n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add n
proc parseMacroColon(p: var TParser, x: PNode): PNode =
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
result = x
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
#| (( '=' optInd expr )
#| / ( expr ^+ comma
#| doBlocks
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
#| / macroColon
#| ))?
inc p.inPragma
var a = simpleExpr(p)
dec p.inPragma
if p.tok.tokType == tkEquals:
getTok(p)
optInd(p, result)
@@ -1056,37 +1185,7 @@ proc parseExprStmt(p: var TParser): PNode =
result = makeCall(result)
parseDoBlocks(p, result)
return result
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
result = parseMacroColon(p, result)
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
result = parseExpr(p)
@@ -1169,8 +1268,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
if p.tok.tokType == tkComment:
skipComment(p, result)
addSon(result, ast.emptyNode)
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
p.tok.tokType == tkEof:
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
# NL terminates:
addSon(result, ast.emptyNode)
else:
@@ -1378,7 +1476,7 @@ proc parseGenericParamList(p: var TParser): PNode =
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
@@ -1433,7 +1531,7 @@ proc parseSection(p: var TParser, kind: TNodeKind,
defparser: TDefParser): PNode =
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
result = newNodeP(kind, p)
getTok(p)
if kind != nkTypeSection: getTok(p)
skipComment(p, result)
if realInd(p):
withInd(p):
@@ -1633,12 +1731,15 @@ proc parseTypeClassParam(p: var TParser): PNode =
result = p.parseSymbol
proc parseTypeClass(p: var TParser): PNode =
#| typeClassParam = ('var')? symbol
#| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
#| &IND{>} stmt
result = newNodeP(nkTypeClassTy, p)
getTok(p)
var args = newNode(nkArgList)
addSon(result, args)
addSon(args, p.parseTypeClassParam)
while p.tok.TokType == tkComma:
while p.tok.tokType == tkComma:
getTok(p)
addSon(args, p.parseTypeClassParam)
if p.tok.tokType == tkCurlyDotLe and p.validInd:
@@ -1663,13 +1764,6 @@ proc parseTypeClass(p: var TParser): PNode =
else:
addSon(result, parseStmt(p))
proc parseDistinct(p: var TParser): PNode =
#| distinct = 'distinct' optInd typeDesc
result = newNodeP(nkDistinctTy, p)
getTok(p)
optInd(p, result)
addSon(result, parseTypeDesc(p))
proc parseTypeDef(p: var TParser): PNode =
#| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
#| indAndComment?
@@ -1791,7 +1885,16 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkMacro: result = parseRoutine(p, nkMacroDef)
of tkTemplate: result = parseRoutine(p, nkTemplateDef)
of tkConverter: result = parseRoutine(p, nkConverterDef)
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
of tkType:
getTok(p)
if p.tok.tokType == tkParLe:
getTok(p)
result = newNodeP(nkTypeOfExpr, p)
result.addSon(primary(p, pmTypeDesc))
eat(p, tkParRi)
result = parseOperators(p, result, -1, pmNormal)
else:
result = parseSection(p, nkTypeSection, parseTypeDef)
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
@@ -1809,16 +1912,16 @@ proc parseStmt(p: var TParser): PNode =
withInd(p):
while true:
if p.tok.indent == p.currInd:
nil
elif p.tok.tokType == tkSemicolon:
discard
elif p.tok.tokType == tkSemiColon:
getTok(p)
if p.tok.indent < 0 or p.tok.indent == p.currInd: discard
else: break
else:
if p.tok.indent > p.currInd:
if p.tok.indent > p.currInd and p.tok.tokType != tkDot:
parMessage(p, errInvalidIndentation)
break
if p.tok.toktype in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
if p.tok.tokType in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
# XXX this ensures tnamedparamanonproc still compiles;
# deprecate this syntax later
break
@@ -1836,14 +1939,19 @@ proc parseStmt(p: var TParser): PNode =
parMessage(p, errComplexStmtRequiresInd)
result = ast.emptyNode
else:
result = newNodeP(nkStmtList, p)
while true:
if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)
let a = simpleStmt(p)
if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
result.add(a)
if p.tok.tokType != tkSemicolon: break
getTok(p)
if p.inSemiStmtList > 0:
result = simpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
else:
result = newNodeP(nkStmtList, p)
while true:
if p.tok.indent >= 0:
parMessage(p, errInvalidIndentation)
let a = simpleStmt(p)
if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
result.add(a)
if p.tok.tokType != tkSemiColon: break
getTok(p)
proc parseAll(p: var TParser): PNode =
result = newNodeP(nkStmtList, p)
@@ -1862,11 +1970,11 @@ proc parseTopLevelStmt(p: var TParser): PNode =
result = ast.emptyNode
while true:
if p.tok.indent != 0:
if p.firstTok and p.tok.indent < 0: nil
if p.firstTok and p.tok.indent < 0: discard
else: parMessage(p, errInvalidIndentation)
p.firstTok = false
case p.tok.tokType
of tkSemicolon:
of tkSemiColon:
getTok(p)
if p.tok.indent <= 0: discard
else: parMessage(p, errInvalidIndentation)
@@ -1877,11 +1985,13 @@ proc parseTopLevelStmt(p: var TParser): PNode =
break
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
var stream = LLStreamOpen(s)
var stream = llStreamOpen(s)
stream.lineOffset = line
var parser: TParser
OpenParser(parser, filename, stream)
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces...
openParser(parser, filename, stream, false)
result = parser.parseAll
CloseParser(parser)
closeParser(parser)

View File

@@ -26,7 +26,7 @@ Options:
"""
proc main(infile, outfile: string, flags: set[TParserFlag]) =
var stream = LLStreamOpen(infile, fmRead)
var stream = llStreamOpen(infile, fmRead)
if stream == nil: rawMessage(errCannotOpenFile, infile)
var p: TParser
openParser(p, infile, stream, flags)

View File

@@ -78,7 +78,7 @@ type
proc getTok*(L: var TLexer, tok: var TToken)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc `$`*(tok: TToken): string
# implementation
@@ -109,17 +109,17 @@ proc getLineInfo*(L: TLexer): TLineInfo =
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
msgs.GlobalError(getLineInfo(L), msg, arg)
msgs.globalError(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
msgs.GlobalError(info, msg, arg)
msgs.globalError(info, msg, arg)
proc TokKindToStr*(k: TTokKind): string =
proc tokKindToStr*(k: TTokKind): string =
case k
of pxEof: result = "[EOF]"
of firstKeyword..lastKeyword:
result = keywords[ord(k)-ord(firstKeyword)]
result = Keywords[ord(k)-ord(firstKeyword)]
of pxInvalid, pxComment, pxStrLit: result = "string literal"
of pxCommand: result = "{@"
of pxAmp: result = "{&"
@@ -160,9 +160,9 @@ proc `$`(tok: TToken): string =
of pxSymbol: result = tok.ident.s
of pxIntLit, pxInt64Lit: result = $tok.iNumber
of pxFloatLit: result = $tok.fNumber
else: result = TokKindToStr(tok.xkind)
else: result = tokKindToStr(tok.xkind)
proc PrintTok(tok: TToken) =
proc printTok(tok: TToken) =
writeln(stdout, $tok)
proc setKeyword(L: var TLexer, tok: var TToken) =
@@ -177,12 +177,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
add(tok.literal, '_')
Inc(pos)
inc(pos)
L.bufPos = pos
proc isFloatLiteral(s: string): bool =
@@ -199,7 +199,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
return
tok.base = base2
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -221,7 +221,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
proc getNumber16(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 1 # skip $
tok.base = base16
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -261,7 +261,7 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
tok.fnumber = parseFloat(tok.literal)
tok.xkind = pxFloatLit
else:
tok.iNumber = ParseInt(tok.literal)
tok.iNumber = parseInt(tok.literal)
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
tok.xkind = pxInt64Lit
else:
@@ -271,10 +271,10 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
except EOverflow:
lexMessage(L, errNumberOutOfRange, tok.literal)
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR: result = nimlexbase.HandleCR(L, pos)
of LF: result = nimlexbase.HandleLF(L, pos)
of CR: result = nimlexbase.handleCR(L, pos)
of LF: result = nimlexbase.handleLF(L, pos)
else: result = pos
proc getString(L: var TLexer, tok: var TToken) =
@@ -319,7 +319,7 @@ proc getString(L: var TLexer, tok: var TToken) =
xi = (xi * 10) + (ord(buf[pos]) - ord('0'))
inc(pos)
else: lexMessage(L, errInvalidCharacterConstant)
if (xi <= 255): add(tok.literal, Chr(xi))
if (xi <= 255): add(tok.literal, chr(xi))
else: lexMessage(L, errInvalidCharacterConstant)
else:
break
@@ -334,17 +334,17 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
var c = buf[pos]
case c
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
h = h +% Ord(c)
h = h +% ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of 'A'..'Z':
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h +% Ord(c)
h = h +% ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of '_': nil
of '_': discard
else: break
Inc(pos)
inc(pos)
h = h +% h shl 3
h = h xor (h shr 11)
h = h +% h shl 15
@@ -385,7 +385,7 @@ proc scanCurlyComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, "\n#")
of '}':
@@ -405,7 +405,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, "\n#")
of '*':
@@ -428,9 +428,9 @@ proc skip(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of ' ', Tabulator:
Inc(pos) # newline is special:
inc(pos) # newline is special:
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
else:
break # EndOfFile also leaves the loop
@@ -449,7 +449,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
case c
of ';':
tok.xkind = pxSemicolon
Inc(L.bufpos)
inc(L.bufpos)
of '/':
if L.buf[L.bufpos + 1] == '/':
scanLineComment(L, tok)
@@ -458,12 +458,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of ',':
tok.xkind = pxComma
Inc(L.bufpos)
inc(L.bufpos)
of '(':
Inc(L.bufpos)
inc(L.bufpos)
if (L.buf[L.bufPos] == '*'):
if (L.buf[L.bufPos + 1] == '$'):
Inc(L.bufpos, 2)
inc(L.bufpos, 2)
skip(L, tok)
getSymbol(L, tok)
tok.xkind = pxStarDirLe
@@ -481,12 +481,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.xkind = pxStar
of ')':
tok.xkind = pxParRi
Inc(L.bufpos)
inc(L.bufpos)
of '[':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketLe
of ']':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketRi
of '.':
inc(L.bufpos)
@@ -496,21 +496,21 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxDot
of '{':
Inc(L.bufpos)
inc(L.bufpos)
case L.buf[L.bufpos]
of '$':
Inc(L.bufpos)
inc(L.bufpos)
skip(L, tok)
getSymbol(L, tok)
tok.xkind = pxCurlyDirLe
of '&':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxAmp
of '%':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxPer
of '@':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCommand
else: scanCurlyComment(L, tok)
of '+':
@@ -554,7 +554,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of '}':
tok.xkind = pxCurlyDirRi
Inc(L.bufpos)
inc(L.bufpos)
of '\'', '#':
getString(L, tok)
of '$':
@@ -567,4 +567,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.literal = c & ""
tok.xkind = pxInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)

View File

@@ -57,7 +57,7 @@ const
["tbinaryfile", "tfile"], ["strstart", "0"], ["nl", "\"\\n\""],
["tostring", "$"]]
proc ParseUnit*(p: var TParser): PNode
proc parseUnit*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
flags: set[TParserFlag] = {})
proc closeParser*(p: var TParser)
@@ -67,20 +67,20 @@ proc fixRecordDef*(n: var PNode)
# implementation
proc OpenParser(p: var TParser, filename: string,
proc openParser(p: var TParser, filename: string,
inputStream: PLLStream, flags: set[TParserFlag] = {}) =
OpenLexer(p.lex, filename, inputStream)
openLexer(p.lex, filename, inputStream)
initIdTable(p.repl)
for i in countup(low(stdReplacements), high(stdReplacements)):
IdTablePut(p.repl, getIdent(stdReplacements[i][0]),
idTablePut(p.repl, getIdent(stdReplacements[i][0]),
getIdent(stdReplacements[i][1]))
if pfMoreReplacements in flags:
for i in countup(low(nimReplacements), high(nimReplacements)):
IdTablePut(p.repl, getIdent(nimReplacements[i][0]),
idTablePut(p.repl, getIdent(nimReplacements[i][0]),
getIdent(nimReplacements[i][1]))
p.flags = flags
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
proc closeParser(p: var TParser) = closeLexer(p.lex)
proc getTok(p: var TParser) = getTok(p.lex, p.tok)
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
@@ -98,15 +98,15 @@ proc skipCom(p: var TParser, n: PNode) =
parMessage(p, warnCommentXIgnored, p.tok.literal)
getTok(p)
proc ExpectIdent(p: TParser) =
proc expectIdent(p: TParser) =
if p.tok.xkind != pxSymbol:
lexMessage(p.lex, errIdentifierExpected, $(p.tok))
proc Eat(p: var TParser, xkind: TTokKind) =
proc eat(p: var TParser, xkind: TTokKind) =
if p.tok.xkind == xkind: getTok(p)
else: lexMessage(p.lex, errTokenExpected, TokKindToStr(xkind))
else: lexMessage(p.lex, errTokenExpected, tokKindToStr(xkind))
proc Opt(p: var TParser, xkind: TTokKind) =
proc opt(p: var TParser, xkind: TTokKind) =
if p.tok.xkind == xkind: getTok(p)
proc newNodeP(kind: TNodeKind, p: TParser): PNode =
@@ -131,7 +131,7 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
proc createIdentNodeP(ident: PIdent, p: TParser): PNode =
result = newNodeP(nkIdent, p)
var x = PIdent(IdTableGet(p.repl, ident))
var x = PIdent(idTableGet(p.repl, ident))
if x != nil: result.ident = x
else: result.ident = ident
@@ -170,7 +170,7 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
getTok(p)
eat(p, pxCurlyDirRi)
result = parseExpr(p)
if result.kind == nkEmpty: InternalError("emptyNode modified")
if result.kind == nkEmpty: internalError("emptyNode modified")
result.kind = nkCurly
elif p.tok.ident.id == getIdent("cast").id:
getTok(p)
@@ -251,7 +251,7 @@ proc bracketExprList(p: var TParser, first: PNode): PNode =
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(pxBracketRi))
parMessage(p, errTokenExpected, tokKindToStr(pxBracketRi))
break
var a = rangeExpr(p)
skipCom(p, a)
@@ -281,7 +281,7 @@ proc exprListAux(p: var TParser, elemKind: TNodeKind,
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(endtok))
parMessage(p, errTokenExpected, tokKindToStr(endTok))
break
var a = exprColonEqExpr(p, elemKind, sepTok)
skipCom(p, a)
@@ -319,7 +319,7 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokKind,
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(endtok))
parMessage(p, errTokenExpected, tokKindToStr(endTok))
break
var a = qualifiedIdent(p)
skipCom(p, a)
@@ -335,7 +335,7 @@ proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind,
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@@ -466,7 +466,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
eat(p, pxCurlyDirRi)
opNode.ident = getIdent("&")
else:
nil
discard
of pxMinus:
if p.tok.xkind == pxPer:
getTok(p)
@@ -477,7 +477,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
of pxNeq:
opNode.ident = getIdent("!=")
else:
nil
discard
skipCom(p, opNode) # read sub-expression with higher priority
nextop = lowestExprAux(p, v2, opPred)
addSon(node, opNode)
@@ -505,7 +505,7 @@ proc fixExpr(n: PNode): PNode =
(n.sons[2].kind in {nkCharLit, nkStrLit}):
n.sons[0].ident = getIdent("&") # fix operator
else:
nil
discard
if not (n.kind in {nkEmpty..nkNilLit}):
for i in countup(0, sonsLen(n) - 1): result.sons[i] = fixExpr(n.sons[i])
@@ -584,7 +584,7 @@ proc parseIncludeDir(p: var TParser): PNode =
proc definedExprAux(p: var TParser): PNode =
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(getIdent("defined"), p))
ExpectIdent(p)
expectIdent(p)
addSon(result, createIdentNodeP(p.tok.ident, p))
getTok(p)
@@ -603,7 +603,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxCurlyDirLe, pxStarDirLe:
if not isHandledDirective(p): break
else:
nil
discard
addSon(result, parseStmt(p))
if sonsLen(result) == 1: result = result.sons[0]
@@ -732,7 +732,7 @@ proc parseRepeat(p: var TParser): PNode =
addSon(b, c)
addSon(a, b)
if b.sons[0].kind == nkIdent and b.sons[0].ident.id == getIdent("false").id:
nil
discard
else:
addSon(s, a)
addSon(result, s)
@@ -753,7 +753,7 @@ proc parseCase(p: var TParser): PNode =
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
addSon(b, rangeExpr(p))
opt(p, pxComma)
skipcom(p, b)
skipCom(p, b)
eat(p, pxColon)
skipCom(p, b)
addSon(b, parseStmt(p))
@@ -818,7 +818,7 @@ proc parseFor(p: var TParser): PNode =
getTok(p)
b = parseExpr(p)
else:
parMessage(p, errTokenExpected, TokKindToStr(pxTo))
parMessage(p, errTokenExpected, tokKindToStr(pxTo))
addSon(c, a)
addSon(c, b)
eat(p, pxDo)
@@ -840,7 +840,7 @@ proc parseParam(p: var TParser): PNode =
getTok(p)
v = newNodeP(nkVarTy, p)
else:
nil
discard
while true:
case p.tok.xkind
of pxSymbol: a = createIdentNodeP(p.tok.ident, p)
@@ -915,7 +915,7 @@ proc parseCallingConvention(p: var TParser): PNode =
getTok(p)
opt(p, pxSemicolon)
else:
nil
discard
proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
var e: PNode
@@ -1096,7 +1096,7 @@ proc parseRecordCase(p: var TParser): PNode =
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
addSon(b, rangeExpr(p))
opt(p, pxComma)
skipcom(p, b)
skipCom(p, b)
eat(p, pxColon)
skipCom(p, b)
c = newNodeP(nkRecList, p)
@@ -1133,7 +1133,7 @@ proc parseRecordPart(p: var TParser): PNode =
proc exSymbol(n: var PNode) =
case n.kind
of nkPostfix:
nil
discard
of nkPragmaExpr:
exSymbol(n.sons[0])
of nkIdent, nkAccQuoted:
@@ -1154,7 +1154,7 @@ proc fixRecordDef(n: var PNode) =
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
of nkIdentDefs:
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
of nkNilLit, nkEmpty: nil
of nkNilLit, nkEmpty: discard
else: internalError(n.info, "fixRecordDef(): " & $n.kind)
proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
@@ -1168,7 +1168,7 @@ proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
else:
pragmasNode = ident.sons[1]
if pragmasNode.kind != nkPragma:
InternalError(ident.info, "addPragmaToIdent")
internalError(ident.info, "addPragmaToIdent")
addSon(pragmasNode, pragma)
proc parseRecordBody(p: var TParser, result, definition: PNode) =
@@ -1183,15 +1183,15 @@ proc parseRecordBody(p: var TParser, result, definition: PNode) =
if definition != nil:
addPragmaToIdent(definition.sons[0], newIdentNodeP(p.tok.ident, p))
else:
InternalError(result.info, "anonymous record is not supported")
internalError(result.info, "anonymous record is not supported")
getTok(p)
else:
InternalError(result.info, "parseRecordBody")
internalError(result.info, "parseRecordBody")
of pxCommand:
if definition != nil: addPragmaToIdent(definition.sons[0], parseCommand(p))
else: InternalError(result.info, "anonymous record is not supported")
else: internalError(result.info, "anonymous record is not supported")
else:
nil
discard
opt(p, pxSemicolon)
skipCom(p, result)
@@ -1223,7 +1223,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
getTok(p)
if p.tok.xkind == pxCommand:
result = parseCommand(p)
if result.kind != nkTupleTy: InternalError(result.info, "parseTypeDesc")
if result.kind != nkTupleTy: internalError(result.info, "parseTypeDesc")
parseRecordBody(p, result, definition)
var a = lastSon(result) # embed nkRecList directly into nkTupleTy
for i in countup(0, sonsLen(a) - 1):
@@ -1237,7 +1237,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
if definition != nil:
addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p))
else:
InternalError(result.info, "anonymous record is not supported")
internalError(result.info, "anonymous record is not supported")
of pxObject: result = parseRecordOrObject(p, nkObjectTy, definition)
of pxParLe: result = parseEnum(p)
of pxArray:
@@ -1399,7 +1399,7 @@ proc fixVarSection(p: var TParser, counter: PNode) =
proc exSymbols(n: PNode) =
case n.kind
of nkEmpty..nkNilLit: nil
of nkEmpty..nkNilLit: discard
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
of nkWhenStmt, nkStmtList:
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
@@ -1410,7 +1410,7 @@ proc exSymbols(n: PNode) =
exSymbol(n.sons[i].sons[0])
if n.sons[i].sons[2].kind == nkObjectTy:
fixRecordDef(n.sons[i].sons[2])
else: nil
else: discard
proc parseBegin(p: var TParser, result: PNode) =
getTok(p)

View File

@@ -19,12 +19,12 @@ proc verboseOpen(s: PSym): PPassContext =
proc verboseProcess(context: PPassContext, n: PNode): PNode =
result = n
if context != nil: InternalError("logpass: context is not nil")
if context != nil: internalError("logpass: context is not nil")
if gVerbosity == 3:
# system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing)
Message(n.info, hintProcessing, $idgen.gBackendId)
message(n.info, hintProcessing, $idgen.gBackendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
@@ -34,14 +34,14 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
if optDeadCodeElim in gGlobalOptions or n == nil: return
case n.kind
of nkStmtList:
for i in countup(0, sonsLen(n) - 1): discard cleanup(c, n.sons[i])
for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i])
of nkProcDef, nkMethodDef:
if n.sons[namePos].kind == nkSym:
var s = n.sons[namePos].sym
if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s):
s.ast.sons[bodyPos] = ast.emptyNode # free the memory
else:
nil
discard
const cleanupPass* = makePass(process = cleanUp, close = cleanUp)

View File

@@ -30,8 +30,8 @@ type
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
process: TPassProcess, close: TPassClose]
TPassData* = tuple[input: PNode, closeOutput: Pnode]
TPasses* = openarray[TPass]
TPassData* = tuple[input: PNode, closeOutput: PNode]
TPasses* = openArray[TPass]
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
# nodes. These are passed to the other close procedures.
@@ -169,7 +169,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
openPasses(a, module)
if stream == nil:
let filename = fileIdx.toFullPath
s = LLStreamOpen(filename, fmRead)
s = llStreamOpen(filename, fmRead)
if s == nil:
rawMessage(errCannotOpenFile, filename)
return
@@ -195,7 +195,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
if s.kind != llsStdIn: break
closePasses(a)
# id synchronization point for more consistent code generation:
IDsynchronizationPoint(1000)
idSynchronizationPoint(1000)
else:
openPassesCached(a, module, rd)
var n = loadInitSection(rd)

View File

@@ -40,7 +40,7 @@ proc canonKind(n: PNode): TNodeKind =
of nkCallKinds: result = nkCall
of nkStrLit..nkTripleStrLit: result = nkStrLit
of nkFastAsgn: result = nkAsgn
else: nil
else: discard
proc sameKinds(a, b: PNode): bool {.inline.} =
result = a.kind == b.kind or a.canonKind == b.canonKind
@@ -87,22 +87,22 @@ proc matchChoice(c: PPatternContext, p, n: PNode): bool =
if matches(c, p.sons[i], n): return true
proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
var pp = GetLazy(c, param)
var pp = getLazy(c, param)
if pp != nil:
# check if we got the same pattern (already unified):
result = sameTrees(pp, n) #matches(c, pp, n)
elif n.kind == nkArgList or checkTypes(c, param, n):
PutLazy(c, param, n)
putLazy(c, param, n)
result = true
proc gather(c: PPatternContext, param: PSym, n: PNode) =
var pp = GetLazy(c, param)
var pp = getLazy(c, param)
if pp != nil and pp.kind == nkArgList:
pp.add(n)
else:
pp = newNodeI(nkArgList, n.info, 1)
pp.sons[0] = n
PutLazy(c, param, pp)
putLazy(c, param, pp)
proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
# match ``op * param`` or ``op *| param``
@@ -148,7 +148,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
of "*": result = matchNested(c, p, n, rpn=false)
of "**": result = matchNested(c, p, n, rpn=true)
of "~": result = not matches(c, p.sons[1], n)
else: InternalError(p.info, "invalid pattern")
else: internalError(p.info, "invalid pattern")
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
# add(a, b)
elif p.kind == nkCurlyExpr:
@@ -256,7 +256,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
args = newNodeI(nkArgList, n.info)
for i in 1 .. < params.len:
let param = params.sons[i].sym
let x = GetLazy(ctx, param)
let x = getLazy(ctx, param)
# couldn't bind parameter:
if isNil(x): return nil
result.add(x)
@@ -267,7 +267,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
var rs = result.sons[i]
let param = params.sons[i].sym
case whichAlias(param)
of aqNone: nil
of aqNone: discard
of aqShouldAlias:
# it suffices that it aliases for sure with *some* other param:
var ok = false

View File

@@ -10,7 +10,7 @@
import
llstream, lexer, parser, idents, strutils, ast, msgs
proc ParseAll*(p: var TParser): PNode =
proc parseAll*(p: var TParser): PNode =
result = nil
proc parseTopLevelStmt*(p: var TParser): PNode =

View File

@@ -185,13 +185,13 @@ var
targetCPU*, hostCPU*: TSystemCPU
targetOS*, hostOS*: TSystemOS
proc NameToOS*(name: string): TSystemOS
proc NameToCPU*(name: string): TSystemCPU
proc nameToOS*(name: string): TSystemOS
proc nameToCPU*(name: string): TSystemCPU
var
IntSize*: int
intSize*: int
floatSize*: int
PtrSize*: int
ptrSize*: int
tnl*: string # target newline
proc setTarget*(o: TSystemOS, c: TSystemCPU) =
@@ -200,18 +200,18 @@ proc setTarget*(o: TSystemOS, c: TSystemCPU) =
#echo "new Target: OS: ", o, " CPU: ", c
targetCPU = c
targetOS = o
intSize = cpu[c].intSize div 8
floatSize = cpu[c].floatSize div 8
ptrSize = cpu[c].bit div 8
tnl = os[o].newLine
intSize = CPU[c].intSize div 8
floatSize = CPU[c].floatSize div 8
ptrSize = CPU[c].bit div 8
tnl = OS[o].newLine
proc NameToOS(name: string): TSystemOS =
proc nameToOS(name: string): TSystemOS =
for i in countup(succ(osNone), high(TSystemOS)):
if cmpIgnoreStyle(name, OS[i].name) == 0:
return i
result = osNone
proc NameToCPU(name: string): TSystemCPU =
proc nameToCPU(name: string): TSystemCPU =
for i in countup(succ(cpuNone), high(TSystemCPU)):
if cmpIgnoreStyle(name, CPU[i].name) == 0:
return i

View File

@@ -20,49 +20,50 @@ const
const
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGenSym, wInject, wRaises, wTags, wOperator, wDelegator}
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wOperator, wDelegator}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty,
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator}
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
wTags, wOperator}
exprPragmas* = {wLine}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
wRaises, wTags}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGenSym, wInject, wRequiresInit}
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError}
wImportCpp, wImportObjC, wError}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal,
wGenSym, wInject, wCodegenDecl}
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wTags}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
@@ -70,7 +71,7 @@ proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation
proc invalidPragma(n: PNode) =
LocalError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0'
@@ -92,13 +93,27 @@ proc setExternName(s: PSym, extname: string) =
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
proc MakeExternImport(s: PSym, extname: string) =
proc makeExternImport(s: PSym, extname: string) =
setExternName(s, extname)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
proc MakeExternExport(s: PSym, extname: string) =
proc validateExternCName(s: PSym, info: TLineInfo) =
## Validates that the symbol name in s.loc.r is a valid C identifier.
##
## Valid identifiers are those alphanumeric including the underscore not
## starting with a number. If the check fails, a generic error will be
## displayed to the user.
let target = ropeToStr(s.loc.r)
if target.len < 1 or target[0] notin IdentStartChars or
not target.allCharsInSet(IdentChars):
localError(info, errGenerated, "invalid exported symbol")
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname)
# XXX to fix make it work with nimrtl.
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
# validateExternCName(s, info)
incl(s.flags, sfExportc)
proc processImportCompilerProc(s: PSym, extname: string) =
@@ -125,7 +140,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
proc getStrLitNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
else:
@@ -133,7 +148,7 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
case n.sons[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
else:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
@@ -142,12 +157,12 @@ proc expectStrLit(c: PContext, n: PNode): string =
proc expectIntLit(c: PContext, n: PNode): int =
if n.kind != nkExprColonExpr:
LocalError(n.info, errIntLiteralExpected)
localError(n.info, errIntLiteralExpected)
else:
n.sons[1] = c.semConstExpr(c, n.sons[1])
case n.sons[1].kind
of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
else: LocalError(n.info, errIntLiteralExpected)
else: localError(n.info, errIntLiteralExpected)
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
@@ -160,7 +175,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
# liMessage(n.info, errMagicOnlyInSystem)
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
return
var v: string
if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
@@ -169,57 +184,57 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
if substr($m, 1) == v:
s.magic = m
break
if s.magic == mNone: Message(n.info, warnUnknownMagic, v)
if s.magic == mNone: message(n.info, warnUnknownMagic, v)
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
# this assumes that the order of special words and calling conventions is
# the same
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
proc IsTurnedOn(c: PContext, n: PNode): bool =
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind == nkExprColonExpr:
let x = c.semConstBoolExpr(c, n.sons[1])
n.sons[1] = x
if x.kind == nkIntLit: return x.intVal != 0
LocalError(n.info, errOnOrOffExpected)
localError(n.info, errOnOrOffExpected)
proc onOff(c: PContext, n: PNode, op: TOptions) =
if IsTurnedOn(c, n): gOptions = gOptions + op
if isTurnedOn(c, n): gOptions = gOptions + op
else: gOptions = gOptions - op
proc pragmaDeadCodeElim(c: PContext, n: PNode) =
if IsTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
else: excl(c.module.flags, sfDeadCodeElim)
proc pragmaNoForward(c: PContext, n: PNode) =
if IsTurnedOn(c, n): incl(c.module.flags, sfNoForward)
if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
else: excl(c.module.flags, sfNoForward)
proc processCallConv(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
var sw = whichKeyword(n.sons[1].ident)
case sw
of firstCallConv..lastCallConv:
of FirstCallConv..LastCallConv:
POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
else: LocalError(n.info, errCallConvExpected)
else: localError(n.info, errCallConvExpected)
else:
LocalError(n.info, errCallConvExpected)
localError(n.info, errCallConvExpected)
proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
var it = PLib(c.libs.head)
while it != nil:
if it.kind == kind:
if trees.ExprStructuralEquivalent(it.path, path): return it
if trees.exprStructuralEquivalent(it.path, path): return it
it = PLib(it.next)
result = newLib(kind)
result.path = path
Append(c.libs, result)
append(c.libs, result)
if path.kind in {nkStrLit..nkTripleStrLit}:
result.isOverriden = options.isDynLibOverride(path.strVal)
result.isOverriden = options.isDynlibOverride(path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
else:
@@ -229,7 +244,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
if result.kind == nkSym and result.sym.kind == skConst:
result = result.sym.ast # look it up
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
result = newEmptyStrNode(n)
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
@@ -247,7 +262,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
# since we'll be loading the dynlib symbols dynamically, we must use
# a calling convention that doesn't introduce custom name mangling
# cdecl is the default - the user can override this explicitly
if sym.kind in RoutineKinds and sym.typ != nil and
if sym.kind in routineKinds and sym.typ != nil and
sym.typ.callConv == ccDefault:
sym.typ.callConv = ccCDecl
@@ -265,7 +280,7 @@ proc processNote(c: PContext, n: PNode) =
of wWarning:
var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
if x >= 0: nk = TNoteKind(x + ord(warnMin))
else: InvalidPragma(n); return
else: invalidPragma(n); return
else:
invalidPragma(n)
return
@@ -284,27 +299,27 @@ proc processOption(c: PContext, n: PNode): bool =
else:
var sw = whichKeyword(n.sons[0].ident)
case sw
of wChecks: OnOff(c, n, checksOptions)
of wObjChecks: OnOff(c, n, {optObjCheck})
of wFieldchecks: OnOff(c, n, {optFieldCheck})
of wRangechecks: OnOff(c, n, {optRangeCheck})
of wBoundchecks: OnOff(c, n, {optBoundsCheck})
of wOverflowchecks: OnOff(c, n, {optOverflowCheck})
of wNilchecks: OnOff(c, n, {optNilCheck})
of wFloatChecks: OnOff(c, n, {optNanCheck, optInfCheck})
of wNaNchecks: OnOff(c, n, {optNanCheck})
of wInfChecks: OnOff(c, n, {optInfCheck})
of wAssertions: OnOff(c, n, {optAssert})
of wWarnings: OnOff(c, n, {optWarns})
of wHints: OnOff(c, n, {optHints})
of wCallConv: processCallConv(c, n)
of wLinedir: OnOff(c, n, {optLineDir})
of wStacktrace: OnOff(c, n, {optStackTrace})
of wLinetrace: OnOff(c, n, {optLineTrace})
of wDebugger: OnOff(c, n, {optEndb})
of wProfiler: OnOff(c, n, {optProfiler})
of wByRef: OnOff(c, n, {optByRef})
of wDynLib: processDynLib(c, n, nil)
of wChecks: onOff(c, n, ChecksOptions)
of wObjChecks: onOff(c, n, {optObjCheck})
of wFieldChecks: onOff(c, n, {optFieldCheck})
of wRangechecks: onOff(c, n, {optRangeCheck})
of wBoundchecks: onOff(c, n, {optBoundsCheck})
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
of wNilchecks: onOff(c, n, {optNilCheck})
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
of wNanChecks: onOff(c, n, {optNaNCheck})
of wInfChecks: onOff(c, n, {optInfCheck})
of wAssertions: onOff(c, n, {optAssert})
of wWarnings: onOff(c, n, {optWarns})
of wHints: onOff(c, n, {optHints})
of wCallconv: processCallConv(c, n)
of wLinedir: onOff(c, n, {optLineDir})
of wStacktrace: onOff(c, n, {optStackTrace})
of wLinetrace: onOff(c, n, {optLineTrace})
of wDebugger: onOff(c, n, {optEndb})
of wProfiler: onOff(c, n, {optProfiler})
of wByRef: onOff(c, n, {optByRef})
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
invalidPragma(n)
@@ -319,14 +334,14 @@ proc processOption(c: PContext, n: PNode): bool =
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: LocalError(n.info, errNoneSpeedOrSizeExpected)
of wImplicitStatic: OnOff(c, n, {optImplicitStatic})
of wPatterns: OnOff(c, n, {optPatterns})
else: localError(n.info, errNoneSpeedOrSizeExpected)
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
of wPatterns: onOff(c, n, {optPatterns})
else: result = true
proc processPush(c: PContext, n: PNode, start: int) =
if n.sons[start-1].kind == nkExprColonExpr:
LocalError(n.info, errGenerated, "':' after 'push' not supported")
localError(n.info, errGenerated, "':' after 'push' not supported")
var x = newOptionEntry()
var y = POptionEntry(c.optionStack.tail)
x.options = gOptions
@@ -344,7 +359,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1:
LocalError(n.info, errAtPopWithoutPush)
localError(n.info, errAtPopWithoutPush)
else:
gOptions = POptionEntry(c.optionStack.tail).options
gNotes = POptionEntry(c.optionStack.tail).notes
@@ -352,15 +367,15 @@ proc processPop(c: PContext, n: PNode) =
proc processDefine(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
DefineSymbol(n.sons[1].ident.s)
Message(n.info, warnDeprecated, "define")
defineSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "define")
else:
invalidPragma(n)
proc processUndef(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
UndefSymbol(n.sons[1].ident.s)
Message(n.info, warnDeprecated, "undef")
undefSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "undef")
else:
invalidPragma(n)
@@ -372,13 +387,13 @@ proc processCompile(c: PContext, n: PNode) =
var s = expectStrLit(c, n)
var found = findFile(s)
if found == "": found = s
var trunc = ChangeFileExt(found, "")
var trunc = changeFileExt(found, "")
extccomp.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false))
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
var f = expectStrLit(c, n)
if splitFile(f).ext == "": f = addFileExt(f, cc[ccompiler].objExt)
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
var found = findFile(f)
if found == "": found = f # use the default
case feature
@@ -387,16 +402,16 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
extccomp.addFileToLink(libpath / completeCFilePath(found, false))
else: internalError(n.info, "processCommonLink")
proc PragmaBreakpoint(c: PContext, n: PNode) =
proc pragmaBreakpoint(c: PContext, n: PNode) =
discard getOptionalStr(c, n, "")
proc PragmaCheckpoint(c: PContext, n: PNode) =
proc pragmaCheckpoint(c: PContext, n: PNode) =
# checkpoints can be used to debug the compiler; they are not documented
var info = n.info
inc(info.line) # next line is affected!
msgs.addCheckpoint(info)
proc PragmaWatchpoint(c: PContext, n: PNode) =
proc pragmaWatchpoint(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
n.sons[1] = c.semExpr(c, n.sons[1])
else:
@@ -408,7 +423,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
var str = n.sons[1].strVal
if str == "":
LocalError(n.info, errEmptyAsm)
localError(n.info, errEmptyAsm)
return
# now parse the string literal and substitute symbols:
var a = 0
@@ -431,14 +446,14 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
a = c + 1
else: illFormedAst(n)
proc PragmaEmit(c: PContext, n: PNode) =
proc pragmaEmit(c: PContext, n: PNode) =
discard getStrLitNode(c, n)
n.sons[1] = semAsmOrEmit(c, n, '`')
proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n)
proc PragmaUnroll(c: PContext, n: PNode) =
proc pragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
invalidPragma(n)
elif n.kind == nkExprColonExpr:
@@ -448,7 +463,7 @@ proc PragmaUnroll(c: PContext, n: PNode) =
else:
invalidPragma(n)
proc PragmaLine(c: PContext, n: PNode) =
proc pragmaLine(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
n.sons[1] = c.semConstExpr(c, n.sons[1])
let a = n.sons[1]
@@ -458,14 +473,14 @@ proc PragmaLine(c: PContext, n: PNode) =
if x.kind == nkExprColonExpr: x = x.sons[1]
if y.kind == nkExprColonExpr: y = y.sons[1]
if x.kind != nkStrLit:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
elif y.kind != nkIntLit:
LocalError(n.info, errIntLiteralExpected)
localError(n.info, errIntLiteralExpected)
else:
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
n.info.line = int16(y.intVal)
else:
LocalError(n.info, errXExpected, "tuple")
localError(n.info, errXExpected, "tuple")
else:
# sensible default:
n.info = getInfoContext(-1)
@@ -476,11 +491,11 @@ proc processPragma(c: PContext, n: PNode, i: int) =
elif it.sons[0].kind != nkIdent: invalidPragma(n)
elif it.sons[1].kind != nkIdent: invalidPragma(n)
var userPragma = NewSym(skTemplate, it.sons[1].ident, nil, it.info)
var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
var body = newNodeI(nkPragma, n.info)
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
userPragma.ast = body
StrTableAdd(c.userPragmas, userPragma)
strTableAdd(c.userPragmas, userPragma)
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode) =
@@ -498,24 +513,31 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
else:
invalidPragma(n)
proc typeBorrow(sym: PSym, n: PNode) =
if n.kind == nkExprColonExpr:
let it = n.sons[1]
if it.kind != nkAccQuoted:
localError(n.info, "a type can only borrow `.` for now")
incl(sym.typ.flags, tfBorrowDot)
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
var it = n.sons[i]
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
if key.kind == nkIdent:
var userPragma = StrTableGet(c.userPragmas, key.ident)
var userPragma = strTableGet(c.userPragmas, key.ident)
if userPragma != nil:
inc c.InstCounter
if c.InstCounter > 100:
GlobalError(it.info, errRecursiveDependencyX, userPragma.name.s)
inc c.instCounter
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
dec c.InstCounter
dec c.instCounter
else:
var k = whichKeyword(key.ident)
if k in validPragmas:
case k
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"))
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
of wImportCompilerProc:
@@ -534,23 +556,25 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wAlign:
if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it)
if not IsPowerOfTwo(align) and align != 0:
LocalError(it.info, errPowerOfTwoExpected)
if not isPowerOfTwo(align) and align != 0:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.align = align
of wSize:
if sym.typ == nil: invalidPragma(it)
var size = expectIntLit(c, it)
if not IsPowerOfTwo(size) or size <= 0 or size > 8:
LocalError(it.info, errPowerOfTwoExpected)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.size = size
of wNodecl:
noVal(it)
incl(sym.loc.Flags, lfNoDecl)
of wPure, wNoStackFrame:
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
noVal(it)
if sym != nil: incl(sym.flags, sfPure)
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
else: incl(sym.flags, sfPure)
of wVolatile:
noVal(it)
incl(sym.flags, sfVolatile)
@@ -566,20 +590,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wCompileTime:
noVal(it)
incl(sym.flags, sfCompileTime)
incl(sym.loc.Flags, lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(it)
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
noval(it)
noVal(it)
incl(sym.flags, sfMerge)
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.Flags, lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
of wDestructor:
@@ -591,23 +615,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideEffect:
of wSideeffect:
noVal(it)
incl(sym.flags, sfSideEffect)
of wNoReturn:
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
of wDynLib:
of wDynlib:
processDynLib(c, it, sym)
of wCompilerProc:
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
makeExternExport(sym, "$1")
makeExternExport(sym, "$1", it.info)
incl(sym.flags, sfCompilerProc)
incl(sym.flags, sfUsed) # suppress all those stupid warnings
registerCompilerProc(sym)
of wProcvar:
of wProcVar:
noVal(it)
incl(sym.flags, sfProcVar)
incl(sym.flags, sfProcvar)
of wDeprecated:
noVal(it)
if sym != nil: incl(sym.flags, sfDeprecated)
@@ -616,9 +640,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfVarargs)
of wBorrow:
noVal(it)
incl(sym.flags, sfBorrow)
of wBorrow:
if sym.kind == skType:
typeBorrow(sym, it)
else:
noVal(it)
incl(sym.flags, sfBorrow)
of wFinal:
noVal(it)
if sym.typ == nil: invalidPragma(it)
@@ -638,10 +665,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wThread:
noVal(it)
incl(sym.flags, sfThread)
incl(sym.flags, sfProcVar)
incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wHint: Message(it.info, hintUser, expectStrLit(c, it))
of wWarning: Message(it.info, warnUser, expectStrLit(c, it))
of wPacked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfPacked)
of wHint: message(it.info, hintUser, expectStrLit(c, it))
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
of wError:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
@@ -651,17 +682,17 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfError)
else:
LocalError(it.info, errUser, expectStrLit(c, it))
of wFatal: Fatal(it.info, errUser, expectStrLit(c, it))
localError(it.info, errUser, expectStrLit(c, it))
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal)
of wLinkSys: processCommonLink(c, it, linkSys)
of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: PragmaBreakpoint(c, it)
of wWatchpoint: PragmaWatchpoint(c, it)
of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
processPush(c, n, i + 1)
result = true
@@ -679,18 +710,18 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,
wCallConv,
wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
LocalError(it.info, errOptionExpected)
of firstCallConv..lastCallConv:
localError(it.info, errOptionExpected)
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(it)
else: sym.typ.callConv = wordToCallConv(k)
of wEmit: PragmaEmit(c, it)
of wUnroll: PragmaUnroll(c, it)
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(it)
of wEffects:
# is later processed in effect analysis:
@@ -699,6 +730,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wUnchecked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUncheckedArray)
of wUnion:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(it)
if sym.typ == nil: invalidPragma(it)
@@ -706,19 +745,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wByRef:
noVal(it)
if sym == nil or sym.typ == nil:
if processOption(c, it): LocalError(it.info, errOptionExpected)
if processOption(c, it): localError(it.info, errOptionExpected)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy)
of wInject, wGenSym:
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
noVal(it)
if sym == nil: invalidPragma(it)
of wLine: PragmaLine(c, it)
of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wOperator:
if sym == nil: invalidPragma(it)
@@ -732,29 +771,40 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else: invalidPragma(it)
else: processNote(c, it)
proc implictPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =
if sym != nil and sym.kind != skModule:
var it = POptionEntry(c.optionstack.head)
var it = POptionEntry(c.optionStack.head)
while it != nil:
let o = it.otherPragmas
if not o.isNil:
for i in countup(0, sonsLen(o) - 1):
if singlePragma(c, sym, o, i, validPragmas):
InternalError(n.info, "implicitPragmas")
internalError(n.info, "implicitPragmas")
it = it.next.POptionEntry
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
LocalError(n.info, errDynlibRequiresExportc)
var lib = POptionEntry(c.optionstack.tail).dynlib
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(n.info, errDynlibRequiresExportc)
var lib = POptionEntry(c.optionStack.tail).dynlib
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
sfImportc in sym.flags and lib != nil:
incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym)
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil:
return false
for p in n.sons:
var key = if p.kind == nkExprColonExpr: p[0] else: p
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
return true
return false
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return
for i in countup(0, sonsLen(n) - 1):
if singlePragma(c, sym, n, i, validPragmas): break
implictPragmas(c, sym, n, validPragmas)
implicitPragmas(c, sym, n, validPragmas)

View File

@@ -12,12 +12,12 @@
import
strutils, os, options, ast, astalgo, msgs, ropes, idents, passes,
intsets, strtabs
intsets, strtabs, semdata
const
removeTP = false # when true, "nimrod pretty" converts TTyp to Typ.
type
type
TGen = object of TPassContext
module*: PSym
PGen = ref TGen
@@ -29,6 +29,7 @@ type
var
gSourceFiles: seq[TSourceFile] = @[]
gCheckExtern: bool
rules: PStringTable
proc loadFile(info: TLineInfo) =
@@ -44,13 +45,20 @@ proc loadFile(info: TLineInfo) =
gSourceFiles[i].lines.add(line)
proc overwriteFiles*() =
let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on"
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles):
if not gSourceFiles[i].dirty: continue
let newFile = gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
let newFile = if overWrite: gSourceFiles[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
try:
var f = open(newFile, fmWrite)
for line in gSourceFiles[i].lines:
f.writeln(line)
if doStrip:
f.write line.strip(leading = false, trailing = true)
else:
f.write line
f.write("\L")
f.close
except EIO:
rawMessage(errCannotOpenFile, newFile)
@@ -60,18 +68,25 @@ proc `=~`(s: string, a: openArray[string]): bool =
if s.startsWith(x): return true
proc beautifyName(s: string, k: TSymKind): string =
# minimal set of rules here for transition:
# GC_ is allowed
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
if allUpper and k in {skConst, skEnumField, skType}: return s
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# skip leading 'T'
# Types should start with a capital unless builtins like 'int' etc.:
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu"]:
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
"range", "openarray", "varargs", "set", "cfloat"
]:
result.add s[i]
else:
result.add toUpper(s[i])
@@ -81,13 +96,19 @@ proc beautifyName(s: string, k: TSymKind): string =
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
elif '_' in s: result.add(s[i])
else: result.add toLower(s[0])
inc i
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
while i < s.len:
if s[i] == '_':
inc i
result.add toUpper(s[i])
if i > 0 and s[i-1] in {'A'..'Z'}:
# don't skip '_' as it's essential for e.g. 'GC_disable'
result.add('_')
inc i
result.add s[i]
else:
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
@@ -97,8 +118,7 @@ proc beautifyName(s: string, k: TSymKind): string =
proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) =
let beau = beautifyName(s, k)
if s != beau:
Message(info, errGenerated,
"name does not adhere to naming convention; should be: " & beau)
message(info, errGenerated, "name should be: " & beau)
const
Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
@@ -117,13 +137,90 @@ proc differ(line: string, a, b: int, x: string): bool =
inc j
return false
var cannotRename = initIntSet()
proc checkDef*(n: PNode; s: PSym) =
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
proc processSym(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
case n.kind
of nkSym:
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(n.info, s.name.s, s.kind)
proc checkDef(c: PGen; n: PNode) =
if n.kind != nkSym: return
checkDef(n, n.sym)
proc checkUse*(n: PNode, s: PSym) =
if n.info.fileIndex < 0: return
# we simply convert it to what it looks like in the definition
# for consistency
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
let newName = s.name.s
loadFile(n.info)
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
var first = min(n.info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
let last = first+identLen(line, first)-1
if differ(line, first, last, newName):
# last-first+1 != newName.len or
var x = line.substr(0, first-1) & newName & line.substr(last+1)
when removeTP:
# the WinAPI module is full of 'TX = X' which after the substitution
# becomes 'X = X'. We remove those lines:
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
x = ""
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
gSourceFiles[n.info.fileIndex].dirty = true
when false:
var cannotRename = initIntSet()
proc beautifyName(s: string, k: TSymKind): string =
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# skip leading 'T'
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu"]:
result.add s[i]
else:
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
else: result.add toLower(s[0])
inc i
while i < s.len:
if s[i] == '_':
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
proc checkUse(c: PGen; n: PNode) =
if n.info.fileIndex < 0: return
let s = n.sym
# operators stay as they are:
@@ -138,10 +235,11 @@ proc processSym(c: PPassContext, n: PNode): PNode =
loadFile(n.info)
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
var first = n.info.col.int
var first = min(n.info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
if {sfImportc, sfExportc} * s.flags != {}:
@@ -149,8 +247,8 @@ proc processSym(c: PPassContext, n: PNode): PNode =
# name:
if newName != s.name.s and newName != s.loc.r.ropeToStr and
lfFullExternalName notin s.loc.flags:
Message(n.info, errGenerated,
"cannot rename $# to $# due to external name" % [s.name.s, newName])
#Message(n.info, errGenerated,
# "cannot rename $# to $# due to external name" % [s.name.s, newName])
cannotRename.incl(s.id)
return
let last = first+identLen(line, first)-1
@@ -165,14 +263,50 @@ proc processSym(c: PPassContext, n: PNode): PNode =
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
gSourceFiles[n.info.fileIndex].dirty = true
proc check(c: PGen, n: PNode) =
case n.kind
of nkSym: checkUse(n, n.sym)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkDef(c, n[0])
check(c, n.sons[1])
of nkForStmt, nkParForStmt:
let L = n.len
for i in countup(0, L-3):
checkDef(c, n[i])
check(c, n[L-2])
check(c, n[L-1])
of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef,
nkMacroDef, nkConverterDef:
checkDef(c, n[namePos])
for i in namePos+1 .. <n.len: check(c, n.sons[i])
of nkIdentDefs, nkVarTuple:
let a = n
checkMinSonsLen(a, 3)
let L = len(a)
for j in countup(0, L-3): checkDef(c, a.sons[j])
check(c, a.sons[L-2])
check(c, a.sons[L-1])
of nkTypeSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
let a = n.sons[i]
if a.kind == nkCommentStmt: continue
checkSonsLen(a, 3)
checkDef(c, a.sons[0])
check(c, a.sons[1])
check(c, a.sons[2])
else:
for i in 0 .. <n.safeLen:
discard processSym(c, n.sons[i])
for i in 0 .. <n.safeLen: check(c, n.sons[i])
proc processSym(c: PPassContext, n: PNode): PNode =
result = n
check(PGen(c), n)
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on"
result = g
if rules.isNil:
rules = newStringTable(modeStyleInsensitive)

View File

@@ -17,52 +17,76 @@ proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return
for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym:
InternalError(procA.info, "equalGenericParams")
internalError(procA.info, "equalGenericParams")
return
if procB.sons[i].kind != nkSym:
InternalError(procB.info, "equalGenericParams")
internalError(procB.info, "equalGenericParams")
return
let a = procA.sons[i].sym
let b = procB.sons[i].sym
if a.name.id != b.name.id or
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
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
proc SearchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
# Searchs for a forward declaration or a "twin" symbol of fn
# in the symbol table. If the parameter lists are exactly
# the same the sym in the symbol table is returned, else nil.
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.Name)
result = initIdentIter(it, scope.symbols, fn.name)
if isGenericRoutine(fn):
# we simply check the AST; this is imprecise but nearly the best what
# can be done; this doesn't work either though as type constraints are
# not kept in the AST ..
while result != nil:
if result.Kind == fn.kind and isGenericRoutine(result):
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],
if exprStructuralEquivalent(genR, genF) and
exprStructuralEquivalent(result.ast.sons[paramsPos],
fn.ast.sons[paramsPos]) and
equalGenericParams(genR, genF):
return
result = NextIdentIter(it, scope.symbols)
result = nextIdentIter(it, scope.symbols)
else:
while result != nil:
if result.Kind == fn.kind and not isGenericRoutine(result):
if result.kind == fn.kind and not isGenericRoutine(result):
case equalParams(result.typ.n, fn.typ.n)
of paramsEqual:
return
of paramsIncompatible:
LocalError(fn.info, errNotOverloadable, fn.name.s)
localError(fn.info, errNotOverloadable, fn.name.s)
return
of paramsNotEqual:
nil
result = NextIdentIter(it, scope.symbols)
discard
result = nextIdentIter(it, scope.symbols)
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name)
while result != nil:
if result.kind in skProcKinds and
sameType(result.typ, fn.typ, flags): return
result = nextIdentIter(it, scope.symbols)
return nil
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
result = searchForProcNew(c, scope, fn)
when false:
let old = searchForProcOld(c, scope, fn)
if old != result:
echo "Mismatch in searchForProc: ", fn.info
debug fn.typ
debug if result != nil: result.typ else: nil
debug if old != nil: old.typ else: nil
when false:
proc paramsFitBorrow(child, parent: PNode): bool =
var length = sonsLen(child)
@@ -77,7 +101,7 @@ when false:
dcEqOrDistinctOf): return
result = true
proc SearchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searchs for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
var it: TIdentIter

View File

@@ -15,7 +15,7 @@ import
type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds
renderNoPragmas, renderIds, renderNoProcDefs
TRenderFlags* = set[TRenderFlag]
TRenderTok*{.final.} = object
kind*: TTokType
@@ -51,10 +51,17 @@ proc isKeyword*(s: string): bool =
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
result = true
proc renderDefinitionName*(s: PSym): string =
proc renderDefinitionName*(s: PSym, noQuotes = false): string =
## Returns the definition name of the symbol.
##
## If noQuotes is false the symbol may be returned in backticks. This will
## happen if the name happens to be a keyword or the first character is not
## part of the SymStartChars set.
let x = s.name.s
if x[0] in SymStartChars and not renderer.isKeyword(x): result = x
else: result = '`' & x & '`'
if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)):
result = x
else:
result = '`' & x & '`'
const
IndentWidth = 2
@@ -62,7 +69,7 @@ const
MaxLineLen = 80
LineCommentColumn = 30
proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
g.comStack = @[]
g.tokens = @[]
g.indent = 0
@@ -76,7 +83,7 @@ proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
var length = len(g.tokens)
setlen(g.tokens, length + 1)
setLen(g.tokens, length + 1)
g.tokens[length].kind = kind
g.tokens[length].length = int16(len(s))
add(g.buf, s)
@@ -104,16 +111,16 @@ proc optNL(g: var TSrcGen) =
optNL(g, g.indent)
proc indentNL(g: var TSrcGen) =
inc(g.indent, indentWidth)
inc(g.indent, IndentWidth)
g.pendingNL = g.indent
g.lineLen = g.indent
proc Dedent(g: var TSrcGen) =
dec(g.indent, indentWidth)
proc dedent(g: var TSrcGen) =
dec(g.indent, IndentWidth)
assert(g.indent >= 0)
if g.pendingNL > indentWidth:
Dec(g.pendingNL, indentWidth)
Dec(g.lineLen, indentWidth)
if g.pendingNL > IndentWidth:
dec(g.pendingNL, IndentWidth)
dec(g.lineLen, IndentWidth)
proc put(g: var TSrcGen, kind: TTokType, s: string) =
addPendingNL(g)
@@ -127,7 +134,7 @@ proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
addTok(g, kind, s)
g.lineLen = lineLen
proc toNimChar(c: Char): string =
proc toNimChar(c: char): string =
case c
of '\0': result = "\\0"
of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
@@ -236,19 +243,19 @@ proc containsNL(s: string): bool =
of '\x0D', '\x0A':
return true
else:
nil
discard
result = false
proc pushCom(g: var TSrcGen, n: PNode) =
var length = len(g.comStack)
setlen(g.comStack, length + 1)
setLen(g.comStack, length + 1)
g.comStack[length] = n
proc popAllComs(g: var TSrcGen) =
setlen(g.comStack, 0)
setLen(g.comStack, 0)
proc popCom(g: var TSrcGen) =
setlen(g.comStack, len(g.comStack) - 1)
setLen(g.comStack, len(g.comStack) - 1)
const
Space = " "
@@ -269,7 +276,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
if (g.pendingNL < 0) and (len(g.buf) > 0) and
(g.lineLen < LineCommentColumn):
var ml = maxLineLength(n.comment)
if ml + LineCommentColumn <= maxLineLen:
if ml + LineCommentColumn <= MaxLineLen:
put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
@@ -278,7 +285,7 @@ proc gcoms(g: var TSrcGen) =
popAllComs(g)
proc lsub(n: PNode): int
proc litAux(n: PNode, x: biggestInt, size: int): string =
proc litAux(n: PNode, x: BiggestInt, size: int): string =
proc skip(t: PType): PType =
result = t
while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
@@ -295,7 +302,7 @@ proc litAux(n: PNode, x: biggestInt, size: int): string =
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
else: result = $x
proc ulitAux(n: PNode, x: biggestInt, size: int): string =
proc ulitAux(n: PNode, x: BiggestInt, size: int): string =
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
@@ -341,7 +348,7 @@ proc atom(n: PNode): string =
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
else: result = "[type node]"
else:
InternalError("rnimsyn.atom " & $n.kind)
internalError("rnimsyn.atom " & $n.kind)
result = ""
proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
@@ -361,11 +368,11 @@ proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
proc lsub(n: PNode): int =
# computes the length of a tree
if isNil(n): return 0
if n.comment != nil: return maxLineLen + 1
if n.comment != nil: return MaxLineLen + 1
case n.kind
of nkEmpty: result = 0
of nkTripleStrLit:
if containsNL(n.strVal): result = maxLineLen + 1
if containsNL(n.strVal): result = MaxLineLen + 1
else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n))
@@ -424,8 +431,13 @@ proc lsub(n: PNode): int =
of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) +
len("Distinct")
of nkDistinctTy:
result = len("distinct") + (if n.len > 0: lsub(n.sons[0])+1 else: 0)
if n.len > 1:
result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
result += lcomma(n[1])
of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
len("static[]")
of nkTypeDef: result = lsons(n) + 3
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
of nkProcTy: result = lsons(n) + len("proc_")
@@ -438,7 +450,7 @@ proc lsub(n: PNode): int =
result = len("enum")
of nkEnumFieldDef: result = lsons(n) + 3
of nkVarSection, nkLetSection:
if sonsLen(n) > 1: result = maxLineLen + 1
if sonsLen(n) > 1: result = MaxLineLen + 1
else: result = lsons(n) + len("var_")
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
@@ -459,10 +471,10 @@ proc lsub(n: PNode): int =
if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
of nkExceptBranch:
result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
else: result = maxLineLen + 1
else: result = MaxLineLen + 1
proc fits(g: TSrcGen, x: int): bool =
result = x + g.lineLen <= maxLineLen
result = x + g.lineLen <= MaxLineLen
type
TSubFlag = enum
@@ -487,7 +499,7 @@ proc hasCom(n: PNode): bool =
result = false
if n.comment != nil: return true
case n.kind
of nkEmpty..nkNilLit: nil
of nkEmpty..nkNilLit: discard
else:
for i in countup(0, sonsLen(n) - 1):
if hasCom(n.sons[i]): return true
@@ -501,7 +513,7 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
for i in countup(start, sonsLen(n) + theEnd):
var c = i < sonsLen(n) + theEnd
var sublen = lsub(n.sons[i]) + ord(c)
if not fits(g, sublen) and (ind + sublen < maxLineLen): optNL(g, ind)
if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
let oldLen = g.tokens.len
gsub(g, n.sons[i])
if c:
@@ -515,21 +527,21 @@ proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = - 1) =
var ind: int
if rfInConstExpr in c.flags:
ind = g.indent + indentWidth
ind = g.indent + IndentWidth
else:
ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd)
proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
var ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd)
proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
var ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd, tkSemicolon)
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = - 1) =
@@ -552,20 +564,23 @@ proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
if not result:
# check further
for i in countup(start, sonsLen(n) + theEnd):
if (lsub(n.sons[i]) > maxLineLen):
if (lsub(n.sons[i]) > MaxLineLen):
result = true
break
proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
if n.kind == nkEmpty: return
if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr):
indentNL(g)
for i in countup(0, sonsLen(n) - 1):
proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
if n.kind == nkEmpty: return
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
if doIndent: indentNL(g)
for i in countup(0, sonsLen(n) - 1):
optNL(g)
gsub(g, n.sons[i])
if n.sons[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
gstmts(g, n.sons[i], c, doIndent=false)
else:
gsub(g, n.sons[i])
gcoms(g)
dedent(g)
else:
if doIndent: dedent(g)
else:
if rfLongMode in c.flags: indentNL(g)
gsub(g, n)
gcoms(g)
@@ -577,7 +592,7 @@ proc gif(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0].sons[0])
initContext(c)
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0].sons[1], c)
@@ -592,7 +607,7 @@ proc gwhile(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[1], c)
@@ -601,7 +616,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
var c: TContext
put(g, tkCurlyLe, "{")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -612,7 +627,7 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[1], c)
@@ -622,7 +637,7 @@ proc gtry(g: var TSrcGen, n: PNode) =
put(g, tkTry, "try")
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -635,7 +650,7 @@ proc gfor(g: var TSrcGen, n: PNode) =
initContext(c)
if longMode(n) or
(lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
maxLineLen):
MaxLineLen):
incl(c.flags, rfLongMode)
gcomma(g, n, c, 0, - 3)
put(g, tkSpaces, Space)
@@ -650,7 +665,7 @@ proc gmacro(g: var TSrcGen, n: PNode) =
initContext(c)
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g)
gsons(g, n, c, 1)
@@ -701,6 +716,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
gcoms(g)
dedent(g)
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
putWithSpace(g, tkGeneric, "generic")
gsons(g, n[0], c) # arglist
gsub(g, n[1]) # pragmas
gsub(g, n[2]) # of
gcoms(g)
indentNL(g)
gcoms(g)
gstmts(g, n[3], c)
dedent(g)
proc gblock(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
@@ -710,7 +738,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
else:
put(g, tkBlock, "block")
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g)
# XXX I don't get why this is needed here! gstmts should already handle this!
@@ -723,7 +751,7 @@ proc gstaticStmt(g: var TSrcGen, n: PNode) =
putWithSpace(g, tkStatic, "static")
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -769,7 +797,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
if n.comment != nil: pushCom(g, n)
case n.kind # atoms:
of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
of nkEmpty: nil
of nkEmpty: discard
of nkType: put(g, tkInvalid, atom(n))
of nkSym, nkIdent: gident(g, n)
of nkIntLit: put(g, tkIntLit, atom(n))
@@ -817,7 +845,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParRi, ")")
of nkStaticExpr:
put(g, tkStatic, "static")
put(g, tkSpaces, space)
put(g, tkSpaces, Space)
gsub(g, n.sons[0])
of nkBracketExpr:
gsub(g, n.sons[0])
@@ -834,7 +862,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gcomma(g, n, 1)
of nkCommand:
gsub(g, n.sons[0])
put(g, tkSpaces, space)
put(g, tkSpaces, Space)
gcomma(g, n, 1)
of nkExprEqExpr, nkAsgn, nkFastAsgn:
gsub(g, n.sons[0])
@@ -941,7 +969,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkPrefix:
gsub(g, n.sons[0])
if n.len > 1:
put(g, tkSpaces, space)
put(g, tkSpaces, Space)
if n.sons[1].kind == nkInfix:
put(g, tkParLe, "(")
gsub(g, n.sons[1])
@@ -1002,9 +1030,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
else:
put(g, tkVar, "var")
of nkDistinctTy:
if sonsLen(n) > 0:
if n.len > 0:
putWithSpace(g, tkDistinct, "distinct")
gsub(g, n.sons[0])
if n.len > 1:
if n[1].kind == nkWith:
putWithSpace(g, tkWith, " with")
else:
putWithSpace(g, tkWithout, " without")
gcomma(g, n[1])
else:
put(g, tkDistinct, "distinct")
of nkTypeDef:
@@ -1054,6 +1088,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0])
else:
put(g, tkShared, "shared")
of nkStaticTy:
put(g, tkStatic, "static")
put(g, tkBracketLe, "[")
if n.len > 0:
gsub(g, n.sons[0])
put(g, tkBracketRi, "]")
of nkEnumTy:
if sonsLen(n) > 0:
putWithSpace(g, tkEnum, "enum")
@@ -1070,7 +1110,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[1])
of nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext)
of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
of nkIfStmt:
putWithSpace(g, tkIf, "if")
gif(g, n)
@@ -1086,22 +1126,22 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkStaticStmt: gstaticStmt(g, n)
of nkAsmStmt: gasm(g, n)
of nkProcDef:
putWithSpace(g, tkProc, "proc")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
gproc(g, n)
of nkConverterDef:
putWithSpace(g, tkConverter, "converter")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
gproc(g, n)
of nkMethodDef:
putWithSpace(g, tkMethod, "method")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
gproc(g, n)
of nkIteratorDef:
putWithSpace(g, tkIterator, "iterator")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
gproc(g, n)
of nkMacroDef:
putWithSpace(g, tkMacro, "macro")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
gproc(g, n)
of nkTemplateDef:
putWithSpace(g, tkTemplate, "template")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
gproc(g, n)
of nkTypeSection:
gsection(g, n, emptyContext, tkType, "type")
@@ -1247,9 +1287,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkBracketLe, "[")
gcomma(g, n)
put(g, tkBracketRi, "]")
of nkMetaNode_Obsolete:
put(g, tkParLe, "(META|")
gsub(g, n.sons[0])
put(g, tkParRi, ")")
of nkGotoState, nkState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
gsons(g, n, c)
of nkTypeClassTy:
gTypeClassTy(g, n)
else:
#nkNone, nkMetaNode, nkExplicitTypeListCall:
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
#nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
var g: TSrcGen
@@ -1260,7 +1311,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
proc renderModule(n: PNode, filename: string,
renderFlags: TRenderFlags = {}) =
var
f: tfile
f: TFile
g: TSrcGen
initSrcGen(g, renderFlags)
for i in countup(0, sonsLen(n) - 1):
@@ -1269,7 +1320,7 @@ proc renderModule(n: PNode, filename: string,
case n.sons[i].kind
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
nkCommentStmt: putNL(g)
else: nil
else: discard
gcoms(g)
if optStdout in gGlobalOptions:
write(stdout, g.buf)
@@ -1292,4 +1343,3 @@ proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
inc(r.idx)
else:
kind = tkEof

View File

@@ -184,7 +184,7 @@ proc skipNode(r: PRodReader) =
if par == 0: break
dec par
of '(': inc par
else: nil
else: discard
inc pos
r.pos = pos+1 # skip ')'
@@ -248,7 +248,7 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
if r.s[r.pos] == ')': inc(r.pos)
else: internalError(result.info, "decodeNode: ')' missing")
else:
InternalError(fInfo, "decodeNode: '(' missing " & $r.pos)
internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, fInfo, nil)
@@ -286,7 +286,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
else:
loc.a = 0
if r.s[r.pos] == '>': inc(r.pos)
else: InternalError(info, "decodeLoc " & r.s[r.pos])
else: internalError(info, "decodeLoc " & r.s[r.pos])
proc decodeType(r: PRodReader, info: TLineInfo): PType =
result = nil
@@ -303,10 +303,10 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
setId(result.id)
if debugIds: registerID(result)
else:
InternalError(info, "decodeType: no id")
internalError(info, "decodeType: no id")
# here this also avoids endless recursion for recursive type
IdTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, UnknownLineInfo())
idTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
if r.s[r.pos] == '$':
inc(r.pos)
result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos)))
@@ -335,7 +335,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
if r.s[r.pos] == '(':
inc(r.pos)
if r.s[r.pos] == ')': inc(r.pos)
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
else: internalError(info, "decodeType ^(" & r.s[r.pos])
rawAddSon(result, nil)
else:
var d = decodeVInt(r.s, r.pos)
@@ -347,10 +347,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
new(result)
inc(r.pos)
result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': InternalError("decodeLib: 1")
if r.s[r.pos] != '|': internalError("decodeLib: 1")
inc(r.pos)
result.name = toRope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': InternalError("decodeLib: 2")
if r.s[r.pos] != '|': internalError("decodeLib: 2")
inc(r.pos)
result.path = decodeNode(r, info)
@@ -370,21 +370,21 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
id = decodeVInt(r.s, r.pos)
setId(id)
else:
InternalError(info, "decodeSym: no id")
internalError(info, "decodeSym: no id")
if r.s[r.pos] == '&':
inc(r.pos)
ident = getIdent(decodeStr(r.s, r.pos))
else:
InternalError(info, "decodeSym: no ident")
internalError(info, "decodeSym: no ident")
#echo "decoding: {", ident.s
result = PSym(IdTableGet(r.syms, id))
result = PSym(idTableGet(r.syms, id))
if result == nil:
new(result)
result.id = id
IdTablePut(r.syms, result, result)
idTablePut(r.syms, result, result)
if debugIds: registerID(result)
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
@@ -427,7 +427,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
result.annex = decodeLib(r, info)
if r.s[r.pos] == '#':
inc(r.pos)
result.constraint = decodeNode(r, UnknownLineInfo())
result.constraint = decodeNode(r, unknownLineInfo())
if r.s[r.pos] == '(':
if result.kind in routineKinds:
result.ast = decodeNodeLazyBody(r, result.info, result)
@@ -455,10 +455,10 @@ proc skipSection(r: PRodReader) =
elif c > 0:
dec(c)
of '\0': break # end of file
else: nil
else: discard
inc(r.pos)
else:
InternalError("skipSection " & $r.line)
internalError("skipSection " & $r.line)
proc rdWord(r: PRodReader): string =
result = ""
@@ -472,11 +472,11 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
result.id = id
result.name = getIdent(name)
result.position = r.readerIndex
setID(id) #MessageOut(result.name.s);
setId(id) #MessageOut(result.name.s);
if debugIds: registerID(result)
proc processInterf(r: PRodReader, module: PSym) =
if r.interfIdx == 0: InternalError("processInterf")
if r.interfIdx == 0: internalError("processInterf")
r.pos = r.interfIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
@@ -485,23 +485,23 @@ proc processInterf(r: PRodReader, module: PSym) =
inc(r.pos) # #10
var s = newStub(r, w, key)
s.owner = module
StrTableAdd(module.tab, s)
IdTablePut(r.syms, s, s)
strTableAdd(module.tab, s)
idTablePut(r.syms, s, s)
proc processCompilerProcs(r: PRodReader, module: PSym) =
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
r.pos = r.compilerProcsIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
inc(r.pos)
var key = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
var s = PSym(IdTableGet(r.syms, key))
var s = PSym(idTableGet(r.syms, key))
if s == nil:
s = newStub(r, w, key)
s.owner = module
IdTablePut(r.syms, s, s)
StrTableAdd(rodCompilerProcs, s)
idTablePut(r.syms, s, s)
strTableAdd(rodCompilerprocs, s)
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
var key, val, tmp: int
@@ -516,11 +516,11 @@ proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
else:
key = idx.lastIdxKey + 1
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.lastIdxVal = val
setID(key) # ensure that this id will not be used
setId(key) # ensure that this id will not be used
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
@@ -539,7 +539,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
of cmdNone, cmdDoc, cmdInterpret, cmdPretty, cmdGenDepend, cmdDump,
cmdCheck, cmdParse, cmdScan, cmdIdeTools, cmdDef,
cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun:
nil
discard
# else: trigger recompilation:
result = true
@@ -558,7 +558,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
setId(r.moduleID)
of "ORIGFILE":
inc(r.pos)
r.origFile = decodeStr(r.s, r.pos)
@@ -603,7 +603,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos) # skip ' '
inclCrc = decodeVInt(r.s, r.pos)
if r.reason == rrNone:
if not ExistsFile(w) or (inclCrc != int(crcFromFile(w))):
if not existsFile(w) or (inclCrc != int(crcFromFile(w))):
r.reason = rrInclDeps
if r.s[r.pos] == '\x0A':
inc(r.pos)
@@ -639,7 +639,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
r.initIdx = r.pos + 2 # "(\10"
skipSection(r)
else:
InternalError("invalid section: '" & section &
internalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
#MsgWriteln("skipping section: " & section &
# " at " & $r.line & " in " & r.filename)
@@ -658,7 +658,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
readerIndex: int): PRodReader =
new(result)
try:
result.memFile = memfiles.open(modfilename)
result.memfile = memfiles.open(modfilename)
except EOS:
return nil
result.files = @[]
@@ -670,13 +670,13 @@ proc newRodReader(modfilename: string, crc: TCrc32,
r.line = 1
r.readerIndex = readerIndex
r.filename = modfilename
InitIdTable(r.syms)
initIdTable(r.syms)
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
# is safe:
r.s = cast[cstring](r.memFile.mem)
r.s = cast[cstring](r.memfile.mem)
if startsWith(r.s, "NIM:"):
initIITable(r.index.tab)
initIITable(r.imports.tab) # looks like a ROD file
initIiTable(r.index.tab)
initIiTable(r.imports.tab) # looks like a ROD file
inc(r.pos, 4)
var version = ""
while r.s[r.pos] notin {'\0', '\x0A'}:
@@ -691,12 +691,12 @@ proc newRodReader(modfilename: string, crc: TCrc32,
result = nil
proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
result = PType(IdTableGet(gTypeTable, id))
result = PType(idTableGet(gTypeTable, id))
if result == nil:
# load the type:
var oldPos = r.pos
var d = IITableGet(r.index.tab, id)
if d == invalidKey: InternalError(info, "rrGetType")
var d = iiTableGet(r.index.tab, id)
if d == InvalidKey: internalError(info, "rrGetType")
r.pos = d + r.dataIdx
result = decodeType(r, info)
r.pos = oldPos
@@ -715,7 +715,7 @@ var gMods*: TFileModuleMap = @[]
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
# all compiled modules
if rd.dataIdx == 0: InternalError(info, "dataIdx == 0")
if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
var oldPos = rd.pos
rd.pos = offset + rd.dataIdx
result = decodeSym(rd, info)
@@ -725,8 +725,8 @@ proc findSomeWhere(id: int) =
for i in countup(0, high(gMods)):
var rd = gMods[i].rd
if rd != nil:
var d = IITableGet(rd.index.tab, id)
if d != invalidKey:
var d = iiTableGet(rd.index.tab, id)
if d != InvalidKey:
echo "found id ", id, " in ", gMods[i].filename
proc getReader(moduleId: int): PRodReader =
@@ -736,37 +736,37 @@ proc getReader(moduleId: int): PRodReader =
# problems:
for i in 0 .. <gMods.len:
result = gMods[i].rd
if result != nil and result.moduleId == moduleId: return result
if result != nil and result.moduleID == moduleId: return result
return nil
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
result = PSym(IdTableGet(r.syms, id))
result = PSym(idTableGet(r.syms, id))
if result == nil:
# load the symbol:
var d = IITableGet(r.index.tab, id)
if d == invalidKey:
var d = iiTableGet(r.index.tab, id)
if d == InvalidKey:
# import from other module:
var moduleID = IiTableGet(r.imports.tab, id)
var moduleID = iiTableGet(r.imports.tab, id)
if moduleID < 0:
var x = ""
encodeVInt(id, x)
InternalError(info, "missing from both indexes: +" & x)
internalError(info, "missing from both indexes: +" & x)
var rd = getReader(moduleID)
d = IITableGet(rd.index.tab, id)
if d != invalidKey:
d = iiTableGet(rd.index.tab, id)
if d != InvalidKey:
result = decodeSymSafePos(rd, d, info)
else:
var x = ""
encodeVInt(id, x)
when false: findSomeWhere(id)
InternalError(info, "rrGetSym: no reader found: +" & x)
internalError(info, "rrGetSym: no reader found: +" & x)
else:
# own symbol:
result = decodeSymSafePos(r, d, info)
if result != nil and result.kind == skStub: rawLoadStub(result)
proc loadInitSection(r: PRodReader): PNode =
if r.initIdx == 0 or r.dataIdx == 0: InternalError("loadInitSection")
if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
var oldPos = r.pos
r.pos = r.initIdx
result = newNode(nkStmtList)
@@ -775,7 +775,7 @@ proc loadInitSection(r: PRodReader): PNode =
inc(r.pos) # #10
var p = r.pos
r.pos = d + r.dataIdx
addSon(result, decodeNode(r, UnknownLineInfo()))
addSon(result, decodeNode(r, unknownLineInfo()))
r.pos = p
r.pos = oldPos
@@ -783,24 +783,24 @@ proc loadConverters(r: PRodReader) =
# We have to ensure that no exported converter is a stub anymore, and the
# import mechanism takes care of the rest.
if r.convertersIdx == 0 or r.dataIdx == 0:
InternalError("importConverters")
internalError("importConverters")
r.pos = r.convertersIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
discard rrGetSym(r, d, UnknownLineInfo())
discard rrGetSym(r, d, unknownLineInfo())
if r.s[r.pos] == ' ': inc(r.pos)
proc loadMethods(r: PRodReader) =
if r.methodsIdx == 0 or r.dataIdx == 0:
InternalError("loadMethods")
internalError("loadMethods")
r.pos = r.methodsIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
if r.s[r.pos] == ' ': inc(r.pos)
proc GetCRC*(fileIdx: int32): TCrc32 =
InternalAssert fileIdx >= 0 and fileIdx < gMods.len
proc getCRC*(fileIdx: int32): TCrc32 =
internalAssert fileIdx >= 0 and fileIdx < gMods.len
if gMods[fileIdx].crcDone:
return gMods[fileIdx].crc
@@ -818,14 +818,14 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
# reason has already been computed for this module:
return gMods[fileIdx].reason
let filename = fileIdx.toFilename
var crc = GetCRC(fileIdx)
var crc = getCRC(fileIdx)
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
result = rrNone
var r: PRodReader = nil
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
r = newRodReader(rodfile, crc, fileIdx)
if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else:
processRodFile(r, crc)
result = r.reason
@@ -834,7 +834,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
# NOTE: we need to process the entire module graph so that no ID will
# be used twice! However, compilation speed does not suffer much from
# this, since results are cached.
var res = checkDep(SystemFileIdx)
var res = checkDep(systemFileIdx)
if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i])
@@ -845,7 +845,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
rawMessage(hintProcessing, reasonToFrmt[result] % filename)
if result != rrNone or optForceFullMake in gGlobalOptions:
# recompilation is necessary:
if r != nil: memfiles.close(r.memFile)
if r != nil: memfiles.close(r.memfile)
r = nil
gMods[fileIdx].rd = r
gMods[fileIdx].reason = result # now we know better
@@ -858,11 +858,11 @@ proc handleSymbolFile(module: PSym): PRodReader =
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
discard checkDep(fileIdx)
if gMods[fileIdx].reason == rrEmpty: InternalError("handleSymbolFile")
if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
result = gMods[fileIdx].rd
if result != nil:
module.id = result.moduleID
IdTablePut(result.syms, module, module)
idTablePut(result.syms, module, module)
processInterf(result, module)
processCompilerProcs(result, module)
loadConverters(result)
@@ -871,26 +871,26 @@ proc handleSymbolFile(module: PSym): PRodReader =
module.id = getID()
proc rawLoadStub(s: PSym) =
if s.kind != skStub: InternalError("loadStub")
if s.kind != skStub: internalError("loadStub")
var rd = gMods[s.position].rd
var theId = s.id # used for later check
var d = IITableGet(rd.index.tab, s.id)
if d == invalidKey: InternalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, UnknownLineInfo())
var d = iiTableGet(rd.index.tab, s.id)
if d == InvalidKey: internalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, unknownLineInfo())
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:
InternalError(rs.info, "loadStub: wrong ID")
internalError(rs.info, "loadStub: wrong ID")
#MessageOut('loaded stub: ' + s.name.s);
proc LoadStub*(s: PSym) =
proc loadStub*(s: PSym) =
## loads the stub symbol `s`.
# deactivate the GC here because we do a deep recursion and generate no
# garbage when restoring parts of the object graph anyway.
# Since we die with internal errors if this fails, so no try-finally is
# Since we die with internal errors if this fails, no try-finally is
# necessary.
GC_disable()
rawLoadStub(s)
@@ -912,8 +912,8 @@ proc getBody*(s: PSym): PNode =
s.ast.sons[bodyPos] = result
s.offset = 0
InitIdTable(gTypeTable)
InitStrTable(rodCompilerProcs)
initIdTable(gTypeTable)
initStrTable(rodCompilerprocs)
# viewer:
proc writeNode(f: TFile; n: PNode) =
@@ -1038,7 +1038,7 @@ proc viewFile(rodfile: string) =
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
setId(r.moduleID)
outf.writeln("ID:", $r.moduleID)
of "ORIGFILE":
inc(r.pos)
@@ -1140,12 +1140,12 @@ proc viewFile(rodfile: string) =
outf.write("DATA(\n")
while r.s[r.pos] != ')':
if r.s[r.pos] == '(':
outf.writeNode decodeNode(r, UnknownLineInfo())
outf.writeNode decodeNode(r, unknownLineInfo())
outf.write("\n")
elif r.s[r.pos] == '[':
outf.writeType decodeType(r, UnknownLineInfo())
outf.writeType decodeType(r, unknownLineInfo())
else:
outf.writeSym decodeSym(r, UnknownLineInfo())
outf.writeSym decodeSym(r, unknownLineInfo())
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
@@ -1166,7 +1166,7 @@ proc viewFile(rodfile: string) =
if r.s[r.pos] == ')': inc r.pos
outf.write("<not supported by viewer>)\n")
else:
InternalError("invalid section: '" & section &
internalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
skipSection(r)
if r.s[r.pos] == '\x0A':

View File

@@ -12,7 +12,7 @@ import strutils
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.}
proc ToStrMaxPrecision*(f: BiggestFloat): string =
proc toStrMaxPrecision*(f: BiggestFloat): string =
if f != f:
result = "NAN"
elif f == 0.0:
@@ -36,7 +36,7 @@ proc hexChar(c: char, xi: var int) =
of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
else: nil
else: discard
proc decodeStr*(s: cstring, pos: var int): string =
var i = pos
@@ -119,7 +119,7 @@ template decodeIntImpl() =
proc decodeVInt*(s: cstring, pos: var int): int =
decodeIntImpl()
proc decodeVBiggestInt*(s: cstring, pos: var int): biggestInt =
proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
decodeIntImpl()
iterator decodeVIntArray*(s: cstring): int =

View File

@@ -56,7 +56,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
if w.files[i] == filename:
return i
result = len(w.files)
setlen(w.files, result + 1)
setLen(w.files, result + 1)
w.files[result] = filename
template filename*(w: PRodWriter): string =
@@ -66,8 +66,8 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
new(result)
result.sstack = @[]
result.tstack = @[]
InitIITable(result.index.tab)
InitIITable(result.imports.tab)
initIiTable(result.index.tab)
initIiTable(result.imports.tab)
result.index.r = ""
result.imports.r = ""
result.crc = crc
@@ -101,12 +101,12 @@ proc addInclDep(w: PRodWriter, dep: string) =
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if IiTableGet(w.index.tab, t.id) == invalidKey:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if IiTableGet(w.index.tab, s.id) == invalidKey:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
@@ -120,19 +120,19 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if finfo.fileIndex != n.info.fileIndex:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(n.info)), result)
elif finfo.line != n.info.line:
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
elif finfo.col != n.info.col:
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
# No need to output the file index, as this is the serialization of one
@@ -190,7 +190,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldlen + 1 == result.len:
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
@@ -202,7 +202,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
result.add("[]")
return
# 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, '[')
@@ -210,7 +210,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, UnknownLineInfo(), t.n, result)
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
@@ -292,7 +292,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, UnknownLineInfo(), s.constraint, result)
encodeNode(w, unknownLineInfo(), s.constraint, result)
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
@@ -322,7 +322,7 @@ proc addToIndex(w: var TIndex, key, val: int) =
add(w.r, rodNL)
w.lastIdxKey = key
w.lastIdxVal = val
IiTablePut(w.tab, key, val)
iiTablePut(w.tab, key, val)
const debugWrittenIds = false
@@ -336,9 +336,9 @@ proc symStack(w: PRodWriter): int =
if sfForward in s.flags:
w.sstack[result] = s
inc result
elif IiTableGet(w.index.tab, s.id) == invalidKey:
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
var m = getModule(s)
if m == nil: InternalError("symStack: module nil: " & s.name.s)
if m == nil: internalError("symStack: module nil: " & s.name.s)
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
# put definition in here
var L = w.data.len
@@ -364,7 +364,7 @@ proc symStack(w: PRodWriter): int =
if s.kind == skMethod and sfDispatcher notin s.flags:
if w.methods.len != 0: add(w.methods, ' ')
encodeVInt(s.id, w.methods)
elif IiTableGet(w.imports.tab, s.id) == invalidKey:
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
addToIndex(w.imports, s.id, m.id)
when debugWrittenIds:
if not Contains(debugWritten, s.id):
@@ -374,7 +374,7 @@ proc symStack(w: PRodWriter): int =
debug(m)
InternalError("Symbol referred to but never written")
inc(i)
setlen(w.sstack, result)
setLen(w.sstack, result)
proc typeStack(w: PRodWriter): int =
var i = 0
@@ -383,13 +383,13 @@ proc typeStack(w: PRodWriter): int =
if t.kind == tyForward:
w.tstack[result] = t
inc result
elif IiTableGet(w.index.tab, t.id) == invalidKey:
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
var L = w.data.len
addToIndex(w.index, t.id, L)
encodeType(w, t, w.data)
add(w.data, rodNL)
inc(i)
setlen(w.tstack, result)
setLen(w.tstack, result)
proc processStacks(w: PRodWriter, finalPass: bool) =
var oldS = 0
@@ -401,7 +401,7 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
oldS = slen
oldT = tlen
if finalPass and (oldS != 0 or oldT != 0):
InternalError("could not serialize some forwarded symbols/types")
internalError("could not serialize some forwarded symbols/types")
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
pushSym(w, s)
@@ -416,7 +416,7 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) =
proc addStmt(w: PRodWriter, n: PNode) =
encodeVInt(w.data.len, w.init)
add(w.init, rodNL)
encodeNode(w, UnknownLineInfo(), n, w.data)
encodeNode(w, unknownLineInfo(), n, w.data)
add(w.data, rodNL)
processStacks(w, false)
@@ -534,9 +534,9 @@ proc process(c: PPassContext, n: PNode): PNode =
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef,
nkTemplateDef, nkMacroDef:
var s = n.sons[namePos].sym
if s == nil: InternalError(n.info, "rodwrite.process")
if s == nil: internalError(n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
InternalError(n.info, "rodwrite.process: body is nil")
internalError(n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
addInterfaceSym(w, s)
@@ -549,7 +549,7 @@ proc process(c: PPassContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
var s = a.sons[0].sym
addInterfaceSym(w, s)
# this takes care of enum fields too
@@ -573,11 +573,11 @@ proc process(c: PPassContext, n: PNode): PNode =
of nkPragma:
addStmt(w, n)
else:
nil
discard
proc myOpen(module: PSym): PPassContext =
if module.id < 0: InternalError("rodwrite: module ID not set")
var w = newRodWriter(module.fileIdx.GetCRC, module)
if module.id < 0: internalError("rodwrite: module ID not set")
var w = newRodWriter(module.fileIdx.getCRC, module)
rawAddInterfaceSym(w, module)
result = w

View File

@@ -91,13 +91,13 @@ proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
proc ropeToStr*(p: PRope): string
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
proc RopeEqualsFile*(r: PRope, f: string): bool
proc ropeEqualsFile*(r: PRope, f: string): bool
# returns true if the rope r is the same as the contents of file f
proc RopeInvariant*(r: PRope): bool
proc ropeInvariant*(r: PRope): bool
# exported for debugging
# implementation
var ErrorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
# avoid dependency on msgs.nim
proc ropeLen(a: PRope): int =
@@ -126,7 +126,7 @@ proc resetRopeCache* =
for i in low(cache)..high(cache):
cache[i] = nil
proc RopeInvariant(r: PRope): bool =
proc ropeInvariant(r: PRope): bool =
if r == nil:
result = true
else:
@@ -157,14 +157,14 @@ proc toRope(s: string): PRope =
result = nil
else:
result = insertInCache(s)
assert(RopeInvariant(result))
assert(ropeInvariant(result))
proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
var length = len(rs)
if at > length:
setlen(rs, at + 1)
setLen(rs, at + 1)
else:
setlen(rs, length + 1) # move old rope elements:
setLen(rs, length + 1) # move old rope elements:
for i in countdown(length, at + 1):
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
rs[at] = r
@@ -177,8 +177,8 @@ proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
add(stack, it.right)
it = it.left
assert(it.data != nil)
CopyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
Inc(resultLen, it.length)
copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
inc(resultLen, it.length)
assert(resultLen <= len(result))
proc ropeToStr(p: PRope): string =
@@ -227,13 +227,13 @@ proc writeRope*(f: TFile, c: PRope) =
assert(it.data != nil)
write(f, it.data)
proc WriteRope*(head: PRope, filename: string, useWarning = false) =
var f: tfile
proc writeRope*(head: PRope, filename: string, useWarning = false) =
var f: TFile
if open(f, filename, fmWrite):
if head != nil: WriteRope(f, head)
if head != nil: writeRope(f, head)
close(f)
else:
ErrorHandler(rCannotOpenFile, filename, useWarning)
errorHandler(rCannotOpenFile, filename, useWarning)
var
rnl* = tnl.newRope
@@ -258,12 +258,12 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
num = j
if j > high(args) + 1:
ErrorHandler(rInvalidFormatStr, $(j))
errorHandler(rInvalidFormatStr, $(j))
else:
app(result, args[j - 1])
of 'n':
@@ -273,21 +273,25 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
app(result, rnl)
inc(i)
else:
ErrorHandler(rInvalidFormatStr, $(frmt[i]))
errorHandler(rInvalidFormatStr, $(frmt[i]))
var start = i
while i < length:
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
app(result, substr(frmt, start, i - 1))
assert(RopeInvariant(result))
assert(ropeInvariant(result))
{.push stack_trace: off, line_trace: off.}
proc `~`*(r: string): PRope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
return r.ropef
{.pop.}
when true:
template `~`*(r: string): PRope = r.ropef
else:
{.push stack_trace: off, line_trace: off.}
proc `~`*(r: static[string]): PRope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r.ropef
return r
{.pop.}
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
app(c, ropef(frmt, args))
@@ -295,10 +299,10 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
const
bufSize = 1024 # 1 KB is reasonable
proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
if r.data != nil:
if r.length > bufSize:
ErrorHandler(rTokenTooLong, r.data)
errorHandler(rTokenTooLong, r.data)
return
var readBytes = readBuffer(bin, buf, r.length)
result = readBytes == r.length and
@@ -307,12 +311,12 @@ proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
result = auxRopeEqualsFile(r.left, bin, buf)
if result: result = auxRopeEqualsFile(r.right, bin, buf)
proc RopeEqualsFile(r: PRope, f: string): bool =
var bin: tfile
proc ropeEqualsFile(r: PRope, f: string): bool =
var bin: TFile
result = open(bin, f)
if not result:
return # not equal if file does not exist
var buf = alloc(BufSize)
var buf = alloc(bufSize)
result = auxRopeEqualsFile(r, bin, buf)
if result:
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
@@ -345,7 +349,7 @@ proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
inc(i)
proc crcFromRope(r: PRope): TCrc32 =
result = newCrcFromRopeAux(r, initCrc32)
result = newCrcFromRopeAux(r, InitCrc32)
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
# returns true if overwritten

View File

@@ -9,7 +9,7 @@
## Saturated arithmetic routines. XXX Make part of the stdlib?
proc `|+|`*(a, b: biggestInt): biggestInt =
proc `|+|`*(a, b: BiggestInt): BiggestInt =
## saturated addition.
result = a +% b
if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
@@ -19,7 +19,7 @@ proc `|+|`*(a, b: biggestInt): biggestInt =
else:
result = high(result)
proc `|-|`*(a, b: biggestInt): biggestInt =
proc `|-|`*(a, b: BiggestInt): BiggestInt =
result = a -% b
if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
return result
@@ -28,14 +28,14 @@ proc `|-|`*(a, b: biggestInt): biggestInt =
else:
result = high(result)
proc `|abs|`*(a: biggestInt): biggestInt =
proc `|abs|`*(a: BiggestInt): BiggestInt =
if a != low(a):
if a >= 0: result = a
else: result = -a
else:
result = low(a)
proc `|div|`*(a, b: biggestInt): biggestInt =
proc `|div|`*(a, b: BiggestInt): BiggestInt =
# (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
if b == 0'i64:
# make the same as ``div 1``:
@@ -45,13 +45,13 @@ proc `|div|`*(a, b: biggestInt): biggestInt =
else:
result = a div b
proc `|mod|`*(a, b: biggestInt): biggestInt =
proc `|mod|`*(a, b: BiggestInt): BiggestInt =
if b == 0'i64:
result = a
else:
result = a mod b
proc `|*|`*(a, b: biggestInt): biggestInt =
proc `|*|`*(a, b: BiggestInt): BiggestInt =
var
resAsFloat, floatProd: float64
result = a *% b

View File

@@ -14,8 +14,8 @@ import
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2
semthreads, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity
# implementation
@@ -43,30 +43,33 @@ proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
typeToString(actual) & ") " &
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
if arg.typ.isNil:
LocalError(arg.info, errExprXHasNoType,
localError(arg.info, errExprXHasNoType,
renderTree(arg, {renderNoComments}))
# error correction:
result = copyNode(arg)
result.typ = formal
else:
result = IndexTypesMatch(c, formal, arg.typ, arg)
result = indexTypesMatch(c, formal, arg.typ, arg)
if result == nil:
typeMismatch(arg, formal, arg.typ)
# error correction:
result = copyNode(arg)
result = copyTree(arg)
result.typ = formal
var CommonTypeBegin = PType(kind: tyExpr)
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr)
proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors,
@@ -83,7 +86,9 @@ proc commonType*(x, y: PType): PType =
elif a.kind == tyTypeDesc:
# turn any concrete typedesc into the abstract typedesc type
if a.sons == nil: result = a
else: result = newType(tyTypeDesc, a.owner)
else:
result = newType(tyTypeDesc, a.owner)
rawAddSon(result, newType(tyNone, a.owner))
elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
a.kind == b.kind:
# check for seq[empty] vs. seq[int]
@@ -113,12 +118,13 @@ proc commonType*(x, y: PType): PType =
if a.kind in {tyRef, tyPtr}:
k = a.kind
if b.kind != a.kind: return x
a = a.sons[0]
b = b.sons[0]
a = a.lastSon
b = b.lastSon
if a.kind == tyObject and b.kind == tyObject:
result = commonSuperclass(a, b)
# this will trigger an error later:
if result.isNil: return x
if result.isNil or result == a: return x
if result == b: return y
if k != tyNone:
let r = result
result = newType(k, r.owner)
@@ -134,8 +140,12 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
result = n.sym
InternalAssert sfGenSym in result.flags
InternalAssert result.kind == kind
internalAssert sfGenSym in result.flags
internalAssert result.kind == kind
# when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the
# template; we must fix it here: see #909
result.owner = getCurrOwner()
else:
result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
@@ -146,73 +156,123 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode
proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
if not typeAllowed(typ, skConst):
LocalError(typ.n.info, errXisNoType, typeToString(typ))
localError(typ.n.info, errXisNoType, typeToString(typ))
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc IsOpImpl(c: PContext, n: PNode): PNode
proc isOpImpl(c: PContext, n: PNode): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode
flags: TExprFlags = {}): PNode
proc symFromType(t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent"AnonType", t.owner, info)
result.flags.incl sfAnon
result.typ = t
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info)
result.typ = makeTypeDesc(c, t)
when false:
proc symFromType(t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent"AnonType", t.owner, info)
result.flags.incl sfAnon
result.typ = t
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
result = newEvalContext(c.module, mode)
result.getType = proc (n: PNode): PNode =
result = tryExpr(c, n)
if result == nil:
result = newSymNode(errorSym(c, n))
elif result.typ == nil:
result = newSymNode(getSysSym"void")
else:
result.typ = makeTypeDesc(c, result.typ)
result.handleIsOperator = proc (n: PNode): PNode =
result = isOpImpl(c, n)
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info)
result.typ = makeTypeDesc(c, t)
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
result = newEvalContext(c.module, mode)
result.getType = proc (n: PNode): PNode =
result = tryExpr(c, n)
if result == nil:
result = newSymNode(errorSym(c, n))
elif result.typ == nil:
result = newSymNode(getSysSym"void")
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound:
when true:
if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
result = semExprWithType(c, evaluated)
else:
result.typ = makeTypeDesc(c, result.typ)
result = evaluated
let expectedType = eOrig.typ.skipTypes({tyStatic})
semmacrosanity.annotateType(result, expectedType)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = eOrig.typ
result.handleIsOperator = proc (n: PNode): PNode =
result = IsOpImpl(c, n)
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil: return
proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode =
result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
result = getConstExpr(c.module, e)
if result != nil: return
proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode =
result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
let oldErrorOutputs = errorOutputs
errorOutputs = {}
msgs.gErrorMax = high(int)
try:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
result = nil
else:
result = fixupTypeAfterEval(c, result, e)
except ERecoverableError:
result = nil
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax
errorOutputs = oldErrorOutputs
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
LocalError(n.info, errConstExprExpected)
localError(n.info, errConstExprExpected)
return n
result = getConstExpr(c.module, e)
if result == nil:
result = evalConstExpr(c, c.module, e)
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
if e.info != n.info:
pushInfoContext(n.info)
LocalError(e.info, errConstExprExpected)
localError(e.info, errConstExprExpected)
popInfoContext()
else:
LocalError(e.info, errConstExprExpected)
localError(e.info, errConstExprExpected)
# error correction:
result = e
else:
result = fixupTypeAfterEval(c, result, e)
include hlo, seminst, semcall
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(s.info, errTemplateInstantiationTooNested)
globalError(s.info, errTemplateInstantiationTooNested)
let oldFriend = c.friendModule
c.friendModule = s.owner.getModule
result = n
if s.typ.sons[0] == nil:
@@ -223,7 +283,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
# BUGFIX: we cannot expect a type here, because module aliases would not
# work then (see the ``tmodulealias`` test)
# semExprWithType(c, result)
result = semExpr(c, result)
result = semExpr(c, result, flags)
of tyStmt:
result = semStmt(c, result)
of tyTypeDesc:
@@ -232,22 +292,24 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
else:
result = semExpr(c, result)
result = semExpr(c, result, flags)
result = fitNode(c, s.typ.sons[0], result)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
c.friendModule = oldFriend
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode =
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
markUsed(n, sym)
if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
globalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = c.createEvalContext(emStatic)
#if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym)
result = evalMacroCall(c.module, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags)
proc forceBool(c: PContext, n: PNode): PNode =
result = fitNode(c, getSysType(tyBool), n)
@@ -257,13 +319,21 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
let nn = semExprWithType(c, n)
result = fitNode(c, getSysType(tyBool), nn)
if result == nil:
LocalError(n.info, errConstExprExpected)
localError(n.info, errConstExprExpected)
return nn
result = getConstExpr(c.module, result)
if result == nil:
LocalError(n.info, errConstExprExpected)
localError(n.info, errConstExprExpected)
result = nn
type
TSemGenericFlag = enum
withinBind, withinTypeDesc, withinMixin
TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
include semtypes, semtempl, semgnrc, semstmts, semexprs
proc addCodeForGenerics(c: PContext, n: PNode) =
@@ -271,30 +341,33 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
var prc = c.generics[i].inst.sym
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
InternalError(prc.info, "no code for " & prc.name.s)
internalError(prc.info, "no code for " & prc.name.s)
else:
addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len
proc myOpen(module: PSym): PPassContext =
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.semExpr = semExpr
c.semTryExpr = tryExpr
c.semTryConstExpr = tryConstExpr
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
pushProcCon(c, module)
pushOwner(c.module)
c.importTable = openScope(c)
c.importTable.addSym(module) # a module knows itself
if sfSystemModule in module.flags:
magicsys.SystemModule = module # set global variable!
magicsys.systemModule = module # set global variable!
else:
c.importTable.addSym magicsys.SystemModule # import the "System" identifier
importAllSymbols(c, magicsys.SystemModule)
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
c.topLevelScope = openScope(c)
result = c
@@ -302,7 +375,7 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module)
for m in items(rd.methods): methodDef(m, true)
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = semStmt(c, n)
# BUGFIX: process newly generated generics here, not at the end!
if c.lastGenericIdx < c.generics.len:
@@ -317,7 +390,7 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = buildEchoStmt(c, result)
result = transformStmt(c.module, result)
proc RecoverContext(c: PContext) =
proc recoverContext(c: PContext) =
# clean up in case of a semantic error: We clean up the stacks, etc. This is
# faster than wrapping every stack operation in a 'try finally' block and
# requires far less code.
@@ -329,15 +402,15 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
# no need for an expensive 'try' if we stop after the first error anyway:
if msgs.gErrorMax <= 1:
result = SemStmtAndGenerateGenerics(c, n)
result = semStmtAndGenerateGenerics(c, n)
else:
let oldContextLen = msgs.getInfoContextLen()
let oldInGenericInst = c.InGenericInst
let oldInGenericInst = c.inGenericInst
try:
result = SemStmtAndGenerateGenerics(c, n)
result = semStmtAndGenerateGenerics(c, n)
except ERecoverableError, ESuggestDone:
RecoverContext(c)
c.InGenericInst = oldInGenericInst
recoverContext(c)
c.inGenericInst = oldInGenericInst
msgs.setInfoContextLen(oldContextLen)
if getCurrentException() of ESuggestDone: result = nil
else: result = ast.emptyNode
@@ -346,7 +419,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
proc checkThreads(c: PContext) =
if not needsGlobalAnalysis(): return
for i in 0 .. c.threadEntries.len-1:
semthreads.AnalyseThreadProc(c.threadEntries[i])
semthreads.analyseThreadProc(c.threadEntries[i])
proc myClose(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
@@ -354,7 +427,7 @@ proc myClose(context: PPassContext, n: PNode): PNode =
rawCloseScope(c) # imported symbols; don't check for unused ones!
result = newNode(nkStmtList)
if n != nil:
InternalError(n.info, "n is not nil") #result := n;
internalError(n.info, "n is not nil") #result := n;
addCodeForGenerics(c, result)
if c.module.ast != nil:
result.add(c.module.ast)

View File

@@ -19,7 +19,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.sym == bb.sym:
result = true
else:
nil
discard
# generics have no dispatcher yet, so we need to compare the method
# names; however, the names are equal anyway because otherwise we
# wouldn't even consider them to be overloaded. But even this does
@@ -47,14 +47,14 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
var z: TCandidate
if sym == nil: return
initCandidate(best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope)
initCandidate(c, best, sym, initialBinding, symScope)
initCandidate(c, alt, sym, initialBinding, symScope)
best.state = csNoMatch
while sym != nil:
if sym.kind in filter:
determineType(c, sym)
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym
matches(c, n, orig, z)
if errors != nil:
@@ -64,25 +64,25 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
errors[errors.len - 1].add("\n " & err)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
if sym.kind in skIterators: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: nil
else: discard
sym = nextOverloadIter(o, c, headSymbol)
proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
if c.InCompilesContext > 0:
if c.inCompilesContext > 0:
# fail fast:
GlobalError(n.info, errTypeMismatch, "")
globalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1 + ord(nfDelegate in n.flags)))
add(result, describeArgs(c, n, 1))
add(result, ')')
var candidates = ""
@@ -93,7 +93,7 @@ proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
LocalError(n.Info, errGenerated, result)
localError(n.info, errGenerated, result)
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
for scope in walkScopes(c.currentScope):
@@ -114,7 +114,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
var errors: seq[string]
var usedSyms: seq[PNode]
template pickBest(headSymbol: expr) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors)
@@ -138,38 +138,62 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
let overloadsState = result.state
if overloadsState != csMatch:
if nfDelegate in n.flags:
InternalAssert f.kind == nkIdent
let calleeName = newStrNode(nkStrLit, f.ident.s)
calleeName.info = n.info
if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)
let callOp = newIdentNode(idDelegator, n.info)
n.sons[0..0] = [callOp, calleeName]
orig.sons[0..0] = [callOp, calleeName]
# leave the op head symbol empty,
# we are going to try multiple variants
n.sons[0..1] = [nil, n[1], calleeName]
orig.sons[0..1] = [nil, orig[1], calleeName]
template tryOp(x) =
let op = newIdentNode(getIdent(x), n.info)
n.sons[0] = op
orig.sons[0] = op
pickBest(op)
if nfExplicitCall in n.flags:
tryOp ".()"
if result.state in {csEmpty, csNoMatch}:
tryOp "."
elif nfDotSetter in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen == 3
let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
let callOp = newIdentNode(getIdent".=", n.info)
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
if overloadsState == csEmpty and result.state == csEmpty:
LocalError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
return
elif result.state != csMatch:
if nfExprCall in n.flags:
LocalError(n.info, errExprXCannotBeCalled,
localError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
else:
if {nfDotField, nfDotSetter} * n.flags != {}:
# clean up the inserted ops
n.sons.delete(2)
n.sons[0] = f
errors = @[]
pickBest(f)
NotFoundError(c, n, errors)
notFoundError(c, n, errors)
return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
InternalAssert result.state == csMatch
internalAssert result.state == csMatch
#writeMatches(result)
#writeMatches(alt)
if c.inCompilesContext > 0:
# quick error message for performance of 'compiles' built-in:
GlobalError(n.Info, errGenerated, "ambiguous call")
globalError(n.info, errGenerated, "ambiguous call")
elif gErrorCounter == 0:
# don't cascade errors
var args = "("
@@ -178,7 +202,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
add(args, typeToString(n.sons[i].typ))
add(args, ")")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
args])
@@ -197,19 +221,32 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
for i in 1 .. <n.len:
instGenericConvertersArg(c, n.sons[i], x)
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, arg, nil)
initCandidate(c, m, f)
result = paramTypesMatch(m, f, a, arg, nil)
if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m)
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, n.typ, n, nil)
initCandidate(c, m, formal)
m.coerceDistincts = coerceDistincts
result = paramTypesMatch(m, formal, arg.typ, arg, nil)
if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m)
if result != nil:
# This almost exactly replicates the steps taken by the compiler during
# param matching. It performs an embarassing ammount of back-and-forth
# type jugling, but it's the price to pay for consistency and correctness
result.typ = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass}))
else:
typeMismatch(arg, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
@@ -225,7 +262,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
result = x.call
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
result.typ = finalCallee.typ.sons[0]
if ContainsGenericType(result.typ): result.typ = errorType(c)
if containsGenericType(result.typ): result.typ = errorType(c)
return
result = x.call
instGenericConvertersSons(c, result, x)
@@ -239,13 +276,13 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
# else: result = errorNode(c, n)
proc explicitGenericInstError(n: PNode): PNode =
LocalError(n.info, errCannotInstantiateX, renderTree(n))
localError(n.info, errCannotInstantiateX, renderTree(n))
result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var x: TCandidate
initCandidate(x, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info)
var m: TCandidate
initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n, s)
result = newSymNode(newInst, n.info)
@@ -260,7 +297,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
let expected = safeLen(s.ast.sons[genericParamsPos])
LocalError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
@@ -271,8 +308,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
# if suffices that the candidate has the proper number of generic
if candidate.kind in {skProc, skMethod, skConverter,
skIterator, skClosureIterator}:
# it suffices that the candidate has the proper number of generic
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate))
@@ -283,12 +321,12 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
else:
result = explicitGenericInstError(n)
proc SearchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searchs for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
# New approach: generate fn(x, y, z) where x, y, z have the proper types
# and use the overloading resolution mechanism:
var call = newNode(nkCall)
var call = newNodeI(nkCall, fn.info)
var hasDistinct = false
call.add(newIdentNode(fn.name, fn.info))
for i in 1.. <fn.typ.n.len:

View File

@@ -13,7 +13,7 @@ import
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread, evals
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
type
TOptionEntry* = object of lists.TListEntry # entries to put on a
@@ -21,7 +21,7 @@ type
options*: TOptions
defaultCC*: TCallingConvention
dynlib*: PLib
Notes*: TNoteKinds
notes*: TNoteKinds
otherPragmas*: PNode # every pragma can be pushed
POptionEntry* = ref TOptionEntry
@@ -32,7 +32,7 @@ type
resultSym*: PSym # the result symbol (if we are in a proc)
nestedLoopCounter*: int # whether we are in a loop or not
nestedBlockCounter*: int # whether we are in a block or not
InTryStmt*: int # whether we are in a try statement; works also
inTryStmt*: int # whether we are in a try statement; works also
# in standalone ``except`` and ``finally``
next*: PProcCon # used for stacking procedure contexts
@@ -42,7 +42,7 @@ type
TExprFlag* = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
efAllowDestructor
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
TExprFlags* = set[TExprFlag]
PContext* = ref TContext
@@ -55,16 +55,16 @@ type
friendModule*: PSym # current friend module; may access private data;
# this is used so that generic instantiations
# can access private object fields
InstCounter*: int # to prevent endless instantiations
instCounter*: int # to prevent endless instantiations
threadEntries*: TSymSeq # list of thread entries to check
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!)
InTypeClass*: int # > 0 if we are in a user-defined type class
InGenericContext*: int # > 0 if we are in a generic type
InUnrolledContext*: int # > 0 if we are unrolling a loop
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
InGenericInst*: int # > 0 if we are instantiating a generic
inTypeClass*: int # > 0 if we are in a user-defined type class
inGenericContext*: int # > 0 if we are in a generic type
inUnrolledContext*: int # > 0 if we are unrolling a loop
inCompilesContext*: int # > 0 if we are in a ``compiles`` magic
inGenericInst*: int # > 0 if we are instantiating a generic
converters*: TSymSeq # sequence of converters
patterns*: TSymSeq # sequence of pattern matchers
optionStack*: TLinkedList
@@ -75,15 +75,19 @@ type
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
bufferErrors = false): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files
userPragmas*: TStrTable
evalContext*: PEvalContext
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
# naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
lastGenericIdx*: int # used for the generics stack
@@ -114,8 +118,8 @@ proc scopeDepth*(c: PContext): int {.inline.} =
# owner handling:
proc getCurrOwner*(): PSym
proc PushOwner*(owner: PSym)
proc PopOwner*()
proc pushOwner*(owner: PSym)
proc popOwner*()
# implementation
var gOwners*: seq[PSym] = @[]
@@ -128,20 +132,20 @@ proc getCurrOwner(): PSym =
# BUGFIX: global array is needed!
result = gOwners[high(gOwners)]
proc PushOwner(owner: PSym) =
proc pushOwner(owner: PSym) =
add(gOwners, owner)
proc PopOwner() =
proc popOwner() =
var length = len(gOwners)
if length > 0: setlen(gOwners, length - 1)
else: InternalError("popOwner")
if length > 0: setLen(gOwners, length - 1)
else: internalError("popOwner")
proc lastOptionEntry(c: PContext): POptionEntry =
result = POptionEntry(c.optionStack.tail)
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
if owner == nil:
InternalError("owner is nil")
internalError("owner is nil")
return
var x: PProcCon
new(x)
@@ -160,7 +164,7 @@ proc newOptionEntry(): POptionEntry =
proc newContext(module: PSym): PContext =
new(result)
result.AmbiguousSymbols = initIntset()
result.ambiguousSymbols = initIntSet()
initLinkedList(result.optionStack)
initLinkedList(result.libs)
append(result.optionStack, newOptionEntry())
@@ -172,13 +176,13 @@ proc newContext(module: PSym): PContext =
result.includedFiles = initIntSet()
initStrTable(result.userPragmas)
result.generics = @[]
result.UnknownIdents = initIntSet()
result.unknownIdents = initIntSet()
proc inclSym(sq: var TSymSeq, s: PSym) =
var L = len(sq)
for i in countup(0, L - 1):
if sq[i].id == s.id: return
setlen(sq, L + 1)
setLen(sq, L + 1)
sq[L] = s
proc addConverter*(c: PContext, conv: PSym) =
@@ -198,29 +202,79 @@ proc addToLib(lib: PLib, sym: PSym) =
proc makePtrType(c: PContext, baseType: PType): PType =
result = newTypeS(tyPtr, c)
addSonSkipIntLit(result, baseType.AssertNotNil)
addSonSkipIntLit(result, baseType.assertNotNil)
proc makeVarType(c: PContext, baseType: PType): PType =
result = newTypeS(tyVar, c)
addSonSkipIntLit(result, baseType.AssertNotNil)
addSonSkipIntLit(result, baseType.assertNotNil)
proc makeTypeDesc*(c: PContext, typ: PType): PType =
result = newTypeS(tyTypeDesc, c)
result.addSonSkipIntLit(typ.AssertNotNil)
result.addSonSkipIntLit(typ.assertNotNil)
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = makeTypeDesc(c, typ)
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
return newSymNode(sym, info)
proc newTypeS(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner())
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
result = newTypeS(tyFromExpr, c)
result.n = n
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
sons: seq[PType]): PType =
result = newType(kind, getCurrOwner())
result.sons = sons
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
result = newNodeI(nkStaticExpr, n.info)
result.sons = @[n]
result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
proc makeAndType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyAnd, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
proc makeOrType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyOr, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
proc makeNotType*(c: PContext, t1: PType): PType =
result = newTypeS(tyNot, c)
result.sons = @[t1]
propagateToOwner(result, t1)
result.flags.incl(t1.flags * {tfHasStatic})
proc nMinusOne*(n: PNode): PNode =
result = newNode(nkCall, n.info, @[
newSymNode(getSysMagic("<", mUnaryLt)),
n])
# Remember to fix the procs below this one when you make changes!
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
let intType = getSysType(tyInt)
result = newTypeS(tyRange, c)
result.sons = @[intType]
result.n = newNode(nkRange, n.info, @[
newIntTypeNode(nkIntLit, 0, intType),
makeStaticExpr(c, n.nMinusOne)])
template rangeHasStaticIf*(t: PType): bool =
# this accepts the ranges's node
t.n[1].kind == nkStaticExpr
template getStaticTypeFromRange*(t: PType): PType =
t.n[1][0][1].typ
proc newTypeS(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner())
proc errorType*(c: PContext): PType =
## creates a type representing an error state
result = newTypeS(tyError, c)
@@ -234,7 +288,7 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
dest.owner = getCurrOwner()
dest.size = - 1
proc makeRangeType*(c: PContext; first, last: biggestInt;
proc makeRangeType*(c: PContext; first, last: BiggestInt;
info: TLineInfo; intType = getSysType(tyInt)): PType =
var n = newNodeI(nkRange, info)
addSon(n, newIntTypeNode(nkIntLit, first, intType))
@@ -244,12 +298,12 @@ proc makeRangeType*(c: PContext; first, last: biggestInt;
addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}:
if s.kind in {skProc, skConverter, skMethod, skIterator, skClosureIterator}:
incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis
proc illFormedAst*(n: PNode) =
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc checkSonsLen*(n: PNode, length: int) =
if sonsLen(n) != length: illFormedAst(n)

View File

@@ -9,26 +9,39 @@
## This module implements destructors.
# included from sem.nim
# special marker values that indicates that we are
# 1) AnalyzingDestructor: currently analyzing the type for destructor
# generation (needed for recursive types)
# 2) DestructorIsTrivial: completed the analysis before and determined
# that the type has a trivial destructor
var AnalyzingDestructor, DestructorIsTrivial: PSym
new(AnalyzingDestructor)
new(DestructorIsTrivial)
var analyzingDestructor, destructorIsTrivial: PSym
new(analyzingDestructor)
new(destructorIsTrivial)
var
destructorName = getIdent"destroy_"
destructorParam = getIdent"this_"
destructorPragma = newIdentNode(getIdent"destructor", UnknownLineInfo())
destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
rangeDestructorProc*: PSym
proc instantiateDestructor(c: PContext, typ: PType): bool
proc instantiateDestructor(c: PContext, typ: PType): PType
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
let t = s.typ.sons[1].skipTypes({tyVar})
var t = s.typ.sons[1].skipTypes({tyVar})
if t.kind == tyGenericInvokation:
for i in 1 .. <t.sonsLen:
if t.sons[i].kind != tyGenericParam:
localError(n.info, errDestructorNotGenericEnough)
return
t = t.base
elif t.kind == tyCompositeTypeClass:
t = t.base
if t.kind != tyGenericBody:
localError(n.info, errDestructorNotGenericEnough)
return
t.destructor = s
# automatically insert calls to base classes' destructors
if n.sons[bodyPos].kind != nkEmpty:
@@ -36,15 +49,19 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
# when inheriting directly from object
# there will be a single nil son
if t.sons[i] == nil: continue
if instantiateDestructor(c, t.sons[i]):
let destructableT = instantiateDestructor(c, t.sons[i])
if destructableT != nil:
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
useSym(t.sons[i].destructor),
useSym(destructableT.destructor),
n.sons[paramsPos][1][0]]))
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
if instantiateDestructor(c, field.typ):
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
let destructableT = instantiateDestructor(c, field.typ)
if destructableT != nil:
result = newNode(nkCall, field.info, @[
useSym(field.typ.destructor),
useSym(destructableT.destructor),
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
@@ -55,78 +72,83 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
for i in countup(1, n.len - 1):
# of A, B:
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
let recList = n[i].lastSon
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
template addField(f: expr): stmt =
let stmt = destroyField(c, f, holder)
if stmt != nil:
destroyRecList.addSon(stmt)
inc nonTrivialFields
case recList.kind
of nkSym:
addField(recList.sym)
of nkRecList:
for j in countup(0, recList.len - 1):
addField(recList[j].sym)
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
if stmt == nil:
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
else:
internalAssert false
caseBranch.addSon(destroyRecList)
caseBranch.addSon(stmt)
nonTrivialFields += stmt.len
result.addSon(caseBranch)
# maybe no fields were destroyed?
if nonTrivialFields == 0:
result = nil
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
template maybeAddLine(e: expr): stmt =
let stmt = e
if stmt != nil:
if result == nil: result = newNode(nkStmtList)
result.addSon(stmt)
case field.kind
of nkRecCase:
maybeAddLine destroyCase(c, field, holder)
of nkSym:
maybeAddLine destroySym(c, field.sym, holder)
of nkRecList:
for son in field:
maybeAddLine destroyFieldOrFields(c, son, holder)
else:
internalAssert false
proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object or tuple type
## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt =
if result == nil: result = newNode(nkStmtList)
result.addSon(e)
# XXX: This may be true for some C-imported types such as
# Tposix_spawnattr
if t.n == nil or t.n.sons == nil: return
internalAssert t.n.kind == nkRecList
let destructedObj = newIdentNode(destructorParam, UnknownLineInfo())
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
# call the destructods of all fields
for s in countup(0, t.n.sons.len - 1):
case t.n.sons[s].kind
of nkRecCase:
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
if stmt != nil: addLine(stmt)
of nkSym:
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
if stmt != nil: addLine(stmt)
else:
internalAssert false
result = destroyFieldOrFields(c, t.n, destructedObj)
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors
proc instantiateDestructor(c: PContext, typ: PType): bool =
# returns true if the type already had a user-defined
# destructor or if the compiler generated a default
# member-wise one
var t = skipTypes(typ, {tyConst, tyMutable})
proc instantiateDestructor(c: PContext, typ: PType): PType =
# returns nil if a variable of type `typ` doesn't require a
# destructor. Otherwise, returns the type, which holds the
# destructor that must be used for the varialbe.
# The destructor is either user-defined or automatically
# generated by the compiler in a member-wise fashion.
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
else: t
if t.destructor != nil:
if typeHoldingUserDefinition.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is already defined" problem
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
if typeHoldingUserDefinition.destructor notin
[analyzingDestructor, destructorIsTrivial]:
return typeHoldingUserDefinition
else:
return nil
t = t.skipTypes({tyGenericInst})
case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
if instantiateDestructor(c, t.sons[0]):
if instantiateDestructor(c, t.sons[0]) != nil:
if rangeDestructorProc == nil:
rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
t.destructor = rangeDestructorProc
return true
return t
else:
return false
return nil
of tyTuple, tyObject:
t.destructor = AnalyzingDestructor
t.destructor = analyzingDestructor
let generated = generateDestructor(c, t)
if generated != nil:
internalAssert t.sym != nil
@@ -139,21 +161,21 @@ proc instantiateDestructor(c: PContext, typ: PType): bool =
emptyNode,
newNode(nkIdentDefs, i, @[
newIdentNode(destructorParam, i),
useSym(t.sym),
symNodeFromType(c, makeVarType(c, t), t.sym.info),
emptyNode]),
]),
newNode(nkPragma, i, @[destructorPragma]),
emptyNode,
generated
])
discard semProc(c, fullDef)
internalAssert t.destructor != nil
return true
let semantizedDef = semProc(c, fullDef)
t.destructor = semantizedDef[namePos].sym
return t
else:
t.destructor = DestructorIsTrivial
return false
t.destructor = destructorIsTrivial
return nil
else:
return false
return nil
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
@@ -179,9 +201,11 @@ proc insertDestructors(c: PContext,
varId = varSection[j][0]
varTyp = varId.sym.typ
info = varId.info
if varTyp != nil and instantiateDestructor(c, varTyp) and
sfGlobal notin varId.sym.flags:
if varTyp == nil or sfGlobal in varId.sym.flags: continue
let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil:
var tryStmt = newNodeI(nkTryStmt, info)
if j < totalVars - 1:
@@ -198,11 +222,11 @@ proc insertDestructors(c: PContext,
else:
result.inner = newNodeI(nkStmtList, info)
tryStmt.addSon(result.inner)
tryStmt.addSon(
newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[
useSym(varTyp.destructor),
useSym(destructableT.destructor),
useSym(varId.sym)]))]))
result.outer = newNodeI(nkStmtList, info)

File diff suppressed because it is too large Load Diff

View File

@@ -66,14 +66,14 @@ proc ordinalValToString*(a: PNode): string =
of tyEnum:
var n = t.n
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkSym: InternalError(a.info, "ordinalValToString")
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
var field = n.sons[i].sym
if field.position == x:
if field.ast == nil:
return field.name.s
else:
return field.ast.strVal
InternalError(a.info, "no symbol for ordinal value: " & $x)
internalError(a.info, "no symbol for ordinal value: " & $x)
else:
result = $x
@@ -92,7 +92,7 @@ proc pickIntRange(a, b: PType): PType =
proc isIntRangeOrLit(t: PType): bool =
result = isIntRange(t) or isIntLit(t)
proc pickMinInt(n: PNode): biggestInt =
proc pickMinInt(n: PNode): BiggestInt =
if n.kind in {nkIntLit..nkUInt64Lit}:
result = n.intVal
elif isIntLit(n.typ):
@@ -100,9 +100,9 @@ proc pickMinInt(n: PNode): biggestInt =
elif isIntRange(n.typ):
result = firstOrd(n.typ)
else:
InternalError(n.info, "pickMinInt")
internalError(n.info, "pickMinInt")
proc pickMaxInt(n: PNode): biggestInt =
proc pickMaxInt(n: PNode): BiggestInt =
if n.kind in {nkIntLit..nkUInt64Lit}:
result = n.intVal
elif isIntLit(n.typ):
@@ -110,17 +110,23 @@ proc pickMaxInt(n: PNode): biggestInt =
elif isIntRange(n.typ):
result = lastOrd(n.typ)
else:
InternalError(n.info, "pickMaxInt")
internalError(n.info, "pickMaxInt")
proc makeRange(typ: PType, first, last: biggestInt): PType =
var n = newNode(nkRange)
addSon(n, newIntNode(nkIntLit, min(first, last)))
addSon(n, newIntNode(nkIntLit, max(first, last)))
result = newType(tyRange, typ.owner)
result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRange(typ: PType, first, last: BiggestInt): PType =
let minA = min(first, last)
let maxA = max(first, last)
let lowerNode = newIntNode(nkIntLit, minA)
if typ.kind == tyInt and minA == maxA:
result = getIntLitType(lowerNode)
else:
var n = newNode(nkRange)
addSon(n, lowerNode)
addSon(n, newIntNode(nkIntLit, maxA))
result = newType(tyRange, typ.owner)
result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRangeF(typ: PType, first, last: biggestFloat): PType =
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
var n = newNode(nkRange)
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
@@ -222,13 +228,40 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
commutativeOp(min)
of mMaxI, mMaxI64:
commutativeOp(max)
else: nil
else: discard
discard """
mShlI, mShlI64,
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
"""
proc evalIs(n, a: PNode): PNode =
# XXX: This should use the standard isOpImpl
internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = a.sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
of "iterator":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator in t.flags))
else:
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
let t2 = n[2].typ
var match = sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
# b and c may be nil
result = nil
@@ -276,7 +309,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shl")
else: internalError(n.info, "constant folding for shl")
of mShrI, mShrI64:
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
@@ -284,7 +317,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shr")
else: internalError(n.info, "constant folding for shr")
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
@@ -327,10 +360,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
of mLeSet: result = newIntNodeT(Ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(Ord(equalSets(a, b)), n)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
of mLtSet:
result = newIntNodeT(Ord(containsSets(a, b) and not equalSets(a, b)), n)
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
of mMulSet:
result = nimsets.intersectSets(a, b)
result.info = n.info
@@ -344,7 +377,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = nimsets.symdiffSets(a, b)
result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
of mInSet: result = newIntNodeT(Ord(inSet(a, b)), n)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
of mRepr:
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
@@ -363,19 +396,19 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = copyTree(a)
result.typ = n.typ
of mCompileOption:
result = newIntNodeT(Ord(commands.testCompileOption(a.getStr, n.info)), n)
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
of mCompileOptionArg:
result = newIntNodeT(Ord(
result = newIntNodeT(ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
of mNewString, mNewStringOfCap,
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym:
nil
discard
of mRand:
result = newIntNodeT(math.random(a.getInt.int), n)
else: InternalError(a.info, "evalOp(" & $m & ')')
else: internalError(a.info, "evalOp(" & $m & ')')
proc getConstIfExpr(c: PSym, n: PNode): PNode =
result = nil
@@ -425,13 +458,13 @@ proc leValueConv(a, b: PNode): bool =
case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
else: InternalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit:
case b.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: InternalError(a.info, "leValueConv")
else: InternalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
proc magicCall(m: PSym, n: PNode): PNode =
if sonsLen(n) <= 1: return
@@ -446,8 +479,6 @@ proc magicCall(m: PSym, n: PNode): PNode =
if sonsLen(n) > 3:
c = getConstExpr(m, n.sons[3])
if c == nil: return
else:
b = nil
result = evalOp(s.magic, n, a, b, c)
proc getAppType(n: PNode): PNode =
@@ -460,9 +491,9 @@ proc getAppType(n: PNode): PNode =
else:
result = newStrNodeT("console", n)
proc rangeCheck(n: PNode, value: biggestInt) =
proc rangeCheck(n: PNode, value: BiggestInt) =
if value < firstOrd(n.typ) or value > lastOrd(n.typ):
LocalError(n.info, errGenerated, "cannot convert " & $value &
localError(n.info, errGenerated, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode =
@@ -485,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
result = a
result.typ = n.typ
of tyOpenArray, tyVarargs, tyProc:
nil
discard
else:
result = a
result.typ = n.typ
@@ -511,19 +542,19 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
else:
LocalError(n.info, errIndexOutOfBounds)
of nkBracket, nkMetaNode:
localError(n.info, errIndexOutOfBounds)
of nkBracket:
if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
else: LocalError(n.info, errIndexOutOfBounds)
else: localError(n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if (idx >= 0) and (idx < len(x.strVal)):
result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal):
nil
discard
else:
LocalError(n.info, errIndexOutOfBounds)
else: nil
localError(n.info, errIndexOutOfBounds)
else: discard
proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed
@@ -587,12 +618,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of skType:
result = newSymNodeTypeDesc(s, n.info)
of skGenericParam:
if s.typ.kind == tyExpr:
result = s.typ.n
result.typ = s.typ.sons[0]
if s.typ.kind == tyStatic:
if s.typ.n != nil:
result = s.typ.n
result.typ = s.typ.sons[0]
else:
result = newSymNodeTypeDesc(s, n.info)
else: nil
else: discard
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:
@@ -604,11 +636,12 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
try:
case s.magic
of mNone:
return # XXX: if it has no sideEffect, it should be evaluated
# If it has no sideEffect, it should be evaluated. But not here.
return
of mSizeOf:
var a = n.sons[1]
if computeSize(a.typ) < 0:
LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined,
localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof")
result = nil
elif skipTypes(a.typ, typedescInst).kind in
@@ -644,12 +677,16 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
of mConStrStr:
result = foldConStrStr(m, n)
of mIs:
let a = getConstExpr(m, n[1])
if a != nil and a.kind == nkSym and a.sym.kind == skType:
result = evalIs(n, a)
else:
result = magicCall(m, n)
except EOverflow:
LocalError(n.info, errOverOrUnderflow)
localError(n.info, errOverOrUnderflow)
except EDivByZero:
LocalError(n.info, errConstantDivisionByZero)
localError(n.info, errConstantDivisionByZero)
of nkAddr:
var a = getConstExpr(m, n.sons[0])
if a != nil:
@@ -705,7 +742,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = a # a <= x and x <= b
result.typ = n.typ
else:
LocalError(n.info, errGenerated, `%`(
localError(n.info, errGenerated, `%`(
msgKindToString(errIllegalConvFromXtoY),
[typeToString(n.sons[0].typ), typeToString(n.typ)]))
of nkStringToCString, nkCStringToString:
@@ -727,4 +764,4 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
else:
nil
discard

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -17,11 +17,6 @@
# included from sem.nim
type
TSemGenericFlag = enum
withinBind, withinTypeDesc, withinMixin
TSemGenericFlags = set[TSemGenericFlag]
proc getIdentNode(n: PNode): PNode =
case n.kind
of nkPostfix: result = getIdentNode(n.sons[1])
@@ -31,8 +26,6 @@ proc getIdentNode(n: PNode): PNode =
illFormedAst(n)
result = n
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
@@ -49,17 +42,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skMethod, skIterator, skConverter:
of skProc, skMethod, skIterators, skConverter:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpand(s):
result = semMacroExpr(c, n, n, s, false)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
@@ -73,7 +66,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
result = n
else: result = newSymNode(s, n.info)
proc Lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
result = n
let ident = considerAcc(n)
@@ -96,10 +89,10 @@ proc semGenericStmt(c: PContext, n: PNode,
if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind
of nkIdent, nkAccQuoted:
result = Lookup(c, n, flags, ctx)
result = lookup(c, n, flags, ctx)
of nkDotExpr:
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
var s = QualifiedLookUp(c, n, luf)
var s = qualifiedLookUp(c, n, luf)
if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
of nkEmpty, nkSym..nkNilLit:
@@ -110,7 +103,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# not work. Copying the symbol does not work either because we're already
# the owner of the symbol! What we need to do is to copy the symbol
# in the generic instantiation process...
nil
discard
of nkBind:
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
of nkMixinStmt:
@@ -119,7 +112,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# check if it is an expression macro:
checkMinSonsLen(n, 1)
let fn = n.sons[0]
var s = qualifiedLookup(c, fn, {})
var s = qualifiedLookUp(c, fn, {})
if s == nil and withinMixin notin flags and
fn.kind in {nkIdent, nkAccQuoted} and considerAcc(fn).id notin ctx:
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
@@ -133,14 +126,14 @@ proc semGenericStmt(c: PContext, n: PNode,
case s.kind
of skMacro:
if macroToExpand(s):
result = semMacroExpr(c, n, n, s, false)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
result = n
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
result = n
@@ -148,7 +141,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# symbol lookup ...
of skUnknown, skParam:
# Leave it as an identifier.
of skProc, skMethod, skIterator, skConverter:
of skProc, skMethod, skIterators, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
first = 1
of skGenericParam:
@@ -219,22 +212,20 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a)
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -242,7 +233,7 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): IllFormedAst(a)
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
@@ -251,13 +242,13 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty:
openScope(c)
@@ -278,18 +269,17 @@ proc semGenericStmt(c: PContext, n: PNode,
else: illFormedAst(n)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
of nkObjectTy, nkTupleTy:
nil
discard
of nkFormalParams:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a)
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -311,7 +301,7 @@ proc semGenericStmt(c: PContext, n: PNode,
else: body = n.sons[bodyPos]
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: nil
of nkPragma, nkPragmaExpr: discard
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)

View File

@@ -13,28 +13,27 @@
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
entry: var TInstantiation) =
if n.kind != nkGenericParams:
InternalError(n.info, "instantiateGenericParamList; no generic params")
internalError(n.info, "instantiateGenericParamList; no generic params")
newSeq(entry.concreteTypes, n.len)
for i in countup(0, n.len - 1):
var a = n.sons[i]
for i, a in n.pairs:
if a.kind != nkSym:
InternalError(a.info, "instantiateGenericParamList; no symbol")
internalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyExpr}+tyTypeClasses:
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
continue
var s = newSym(skType, q.name, getCurrOwner(), q.info)
s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(IdTableGet(pt, q.typ))
var t = PType(idTableGet(pt, q.typ))
if t == nil:
if tfRetType in q.typ.flags:
# keep the generic type and allow the return type to be bound
# later by semAsgn in return type inference scenario
t = q.typ
else:
LocalError(a.info, errCannotInstantiateX, s.name.s)
localError(a.info, errCannotInstantiateX, s.name.s)
t = errorType(c)
elif t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
internalError(a.info, "instantiateGenericParamList: " & q.name.s)
elif t.kind == tyGenericInvokation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
@@ -47,10 +46,10 @@ proc sameInstantiation(a, b: TInstantiation): bool =
if a.concreteTypes.len == b.concreteTypes.len:
for i in 0..a.concreteTypes.high:
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
flags = {TypeDescExactMatch}): return
flags = {ExactTypeDescValues}): return
result = true
proc GenericCacheGet(genericSym: Psym, entry: TInstantiation): PSym =
proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
if genericSym.procInstCache != nil:
for inst in genericSym.procInstCache:
if sameInstantiation(entry, inst[]):
@@ -75,41 +74,42 @@ proc removeDefaultParamValues(n: PNode) =
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags:
var x = PSym(IdTableGet(symMap, n.sym))
var x = PSym(idTableGet(symMap, n.sym))
if x == nil:
x = copySym(n.sym, false)
x.owner = owner
IdTablePut(symMap, n.sym, x)
idTablePut(symMap, n.sym, x)
n.sym = x
else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
proc addProcDecls(c: PContext, fn: PSym) =
# get the proc itself in scope (e.g. for recursion)
addDecl(c, fn)
for i in 1 .. <fn.typ.n.len:
var param = fn.typ.n.sons[i].sym
param.owner = fn
addParamOrResult(c, param, fn.kind)
maybeAddResult(c, fn, fn.ast)
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
if n.sons[bodyPos].kind != nkEmpty:
inc c.InGenericInst
inc c.inGenericInst
# add it here, so that recursive generic procs are possible:
addDecl(c, result)
pushProcCon(c, result)
# add params to scope
for i in 1 .. <result.typ.n.len:
var param = result.typ.n.sons[i].sym
param.owner = result
addParamOrResult(c, param, result.kind)
# debug result.typ.n
maybeAddResult(c, result, n)
var b = n.sons[bodyPos]
var symMap: TIdTable
InitIdTable symMap
initIdTable symMap
freshGenSyms(b, result, symMap)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result)
#echo "code instantiated ", result.name.s
excl(result.flags, sfForward)
popProcCon(c)
dec c.InGenericInst
dec c.inGenericInst
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
for i in countup(0, c.generics.len - 1):
@@ -126,147 +126,78 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
localError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType =
InternalAssert invocation.kind == tyGenericInvokation
let cacheHit = searchInstTypes(invocation)
if cacheHit != nil:
result = cacheHit
else:
let s = invocation.sons[0].sym
let oldScope = c.currentScope
c.currentScope = s.typScope
openScope(c)
pushInfoContext(info)
for i in 0 .. <s.typ.n.sons.len:
let genericParam = s.typ.n[i].sym
let symKind = if genericParam.typ.kind == tyExpr: skConst
else: skType
var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr})
boundSym.ast = invocation.sons[i+1].n
addDecl(c, boundSym)
# XXX: copyTree would have been unnecessary here if semTypeNode
# didn't modify its input parameters. Currently, it does modify
# at least the record lists of the passed object and tuple types
var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil)
popInfoContext()
closeScope(c)
c.currentScope = oldScope
if instantiated != nil:
result = invocation
result.kind = tyGenericInst
result.sons.add instantiated
cacheTypeInst result
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
when oUseLateInstantiation:
lateInstantiateGeneric(c, header, info)
else:
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = info
cl.c = c
result = ReplaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
var cl: TReplTypeVars
initIdTable(cl.symMap)
initIdTable(cl.typeMap)
initIdTable(cl.localCache)
cl.info = info
cl.c = c
cl.allowMetaTypes = allowMetaTypes
result = replaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
result = instGenericContainer(c, n.info, header)
proc fixupProcType(c: PContext, genericType: PType,
inst: TInstantiation): PType =
# XXX: This is starting to look suspiciously like ReplaceTypeVarsT
# there are few apparent differences, but maybe the code could be
# moved over.
# * the code here uses the new genericSym.position property when
# doing lookups.
# * the handling of tyTypeDesc seems suspicious in ReplaceTypeVarsT
# typedesc params were previously handled in the second pass of
# semParamList
# * void (nkEmpty) params doesn't seem to be stripped in ReplaceTypeVarsT
result = genericType
if result == nil: return
case genericType.kind
of tyGenericParam, tyTypeClasses:
result = inst.concreteTypes[genericType.sym.position]
of tyTypeDesc:
result = inst.concreteTypes[genericType.sym.position]
if tfUnresolved in genericType.flags:
result = result.sons[0]
of tyExpr:
result = inst.concreteTypes[genericType.sym.position]
of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc,
tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs:
if genericType.sons == nil: return
var head = 0
for i in 0 .. <genericType.sons.len:
let origType = genericType.sons[i]
var changed = fixupProcType(c, origType, inst)
if changed != genericType.sons[i]:
var changed = changed.skipIntLit
if result == genericType:
# the first detected change initializes the result
result = copyType(genericType, genericType.owner, false)
if genericType.n != nil:
result.n = copyTree(genericType.n)
# XXX: doh, we have to treat seq and arrays as special case
# because sometimes the `@` magic will be applied to an empty
# sequence having the type tySequence(tyEmpty)
if changed.kind == tyEmpty and
genericType.kind notin {tyArray, tySequence}:
if genericType.kind == tyProc and i == 0:
# return types of procs are overwritten with nil
changed = nil
else:
# otherwise, `empty` is just erased from the signature
result.sons[i..i] = []
if result.n != nil: result.n.sons[i..i] = []
continue
result.sons[head] = changed
if result.n != nil:
if result.n.kind == nkRecList:
for son in result.n.sons:
if son.typ == origType:
son.typ = changed
son.sym = copySym(son.sym, true)
son.sym.typ = changed
if result.n.kind == nkFormalParams:
if i != 0:
let origParam = result.n.sons[head].sym
var param = copySym(origParam)
param.typ = changed
param.ast = origParam.ast
result.n.sons[head] = newSymNode(param)
# won't be advanced on empty (void) nodes
inc head
proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
# time adding the instantiated proc params into the current scope.
# This is necessary, because the instantiation process may refer to
# these params in situations like this:
# proc foo[Container](a: Container, b: a.type.Item): type(b.x)
#
# Alas, doing this here is probably not enough, because another
# proc signature could appear in the params:
# proc foo[T](a: proc (x: T, b: type(x.y))
#
# The solution would be to move this logic into semtypinst, but
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc
#
addDecl(c, prc)
of tyGenericInvokation:
result = newTypeWithSons(c, tyGenericInvokation, genericType.sons)
for i in 1 .. <genericType.sons.len:
result.sons[i] = fixupProcType(c, result.sons[i], inst)
result = instGenericContainer(c, getInfoContext(-1), result)
pushInfoContext(info)
var cl = initTypeVars(c, pt, info)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
else: nil
for i in 1 .. <result.len:
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
let param = replaceTypeVarsN(cl, originalParams[i])
result.n.sons[i] = param
if param.kind == nkSym:
# XXX: this won't be true for void params
# implement pass-through of void params and
# the "sort by distance to point" container
param.sym.owner = prc
addDecl(c, param.sym)
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
result.n.sons[0] = originalParams[0].copyTree
eraseVoidParams(result)
skipIntLiteralParams(result)
prc.typ = result
maybeAddResult(c, prc, prc.ast)
popInfoContext()
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# no need to instantiate generic templates/macros:
if fn.kind in {skTemplate, skMacro}: return fn
# generates an instantiated proc
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
inc(c.InstCounter)
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
inc(c.instCounter)
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
# NOTE: for access of private fields within generics from a different module
@@ -281,16 +212,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.ast = n
pushOwner(result)
openScope(c)
if n.sons[genericParamsPos].kind == nkEmpty:
InternalError(n.info, "generateInstance")
internalAssert n.sons[genericParamsPos].kind != nkEmpty
n.sons[namePos] = newSymNode(result)
pushInfoContext(info)
var entry = TInstantiation.new
entry.sym = result
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
result.typ = fixupProcType(c, fn.typ, entry[])
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
n.sons[genericParamsPos] = ast.emptyNode
var oldPrc = GenericCacheGet(fn, entry[])
var oldPrc = genericCacheGet(fn, entry[])
if oldPrc == nil:
fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry))
@@ -298,18 +229,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
if isNil(n.sons[bodyPos]):
n.sons[bodyPos] = copyTree(fn.getBody)
if fn.kind != skTemplate:
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
ParamsTypeCheck(c, result.typ)
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
paramsTypeCheck(c, result.typ)
else:
result = oldPrc
popProcCon(c)
popInfoContext()
closeScope(c) # close scope for parameters
popOwner()
#c.currentScope = oldScope
c.friendModule = oldFriend
dec(c.InstCounter)
dec(c.instCounter)
if result.kind == skMethod: finishMethod(c, result)

View File

@@ -0,0 +1,89 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, astalgo, msgs, types
proc ithField(n: PNode, field: int): PSym =
result = nil
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
result = ithField(n.sons[i], field-i)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
result = ithField(n.sons[0], field-1)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field-1)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
of nkSym:
if field == 0: result = n.sym
else: discard
proc annotateType*(n: PNode, t: PType) =
let x = t.skipTypes(abstractInst)
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
case n.kind
of nkPar:
if x.kind == tyObject:
n.typ = t
for i in 0 .. <n.len:
let field = x.n.ithField(i)
if field.isNil: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], field.typ)
elif x.kind == tyTuple:
n.typ = t
for i in 0 .. <n.len:
if i >= x.len: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i])
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
else:
globalError(n.info, "() must have an object or tuple type")
of nkBracket:
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:
globalError(n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:
globalError(n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
else:
globalError(n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
else:
globalError(n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}:
n.typ = t
else:
globalError(n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes:
n.typ = t
else:
globalError(n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -18,7 +18,7 @@ proc expectIntLit(c: PContext, n: PNode): int =
let x = c.semConstExpr(c, n)
case x.kind
of nkIntLit..nkInt64Lit: result = int(x.intVal)
else: LocalError(n.info, errIntLiteralExpected)
else: localError(n.info, errIntLiteralExpected)
proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkPar, n.info, n.typ)
@@ -26,21 +26,34 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.ToFilename
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
line.intVal = ToLinenumber(info)
line.intVal = toLinenumber(info)
result.add(filename)
result.add(line)
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
let typ = operand.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = trait.info
of "arity":
result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context)
result.info = trait.info
else:
internalAssert false
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym
let typArg = n.sons[1].sym
if typArg.kind == skType or
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
let t = n.sons[1].typ
internalAssert t != nil and t.kind == tyTypeDesc
if t.sonsLen > 0:
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n[0], n[1], GetCurrOwner())
result = evalTypeTrait(n[0], t, getCurrOwner())
else:
# a typedesc variable, pass unmodified to evals
result = n
@@ -56,23 +69,23 @@ proc semBindSym(c: PContext, n: PNode): PNode =
let sl = semConstExpr(c, n.sons[1])
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
LocalError(n.sons[1].info, errStringLiteralExpected)
localError(n.sons[1].info, errStringLiteralExpected)
return errorNode(c, n)
let isMixin = semConstExpr(c, n.sons[2])
if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
isMixin.intVal > high(TSymChoiceRule).int:
LocalError(n.sons[2].info, errConstExprExpected)
localError(n.sons[2].info, errConstExprExpected)
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = QualifiedLookUp(c, id)
let s = qualifiedLookUp(c, id)
if s != nil:
# we need to mark all symbols:
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
result.add(sc)
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
@@ -88,7 +101,7 @@ proc semLocals(c: PContext, n: PNode): PNode =
#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}:
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
var field = newSym(skField, it.name, getCurrOwner(), n.info)
field.typ = it.typ.skipTypes({tyGenericInst, tyVar})

View File

@@ -84,10 +84,10 @@ proc initVar(a: PEffects, n: PNode) =
proc initVarViaNew(a: PEffects, n: PNode) =
if n.kind != nkSym: return
let s = n.sym
if {tfNeedsInit, tfNotNil} * s.typ.flags == {tfNotNil}:
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
# 'x' is not nil, but that doesn't mean it's not nil children
# are initialized:
initVarViaNew(a, n)
initVar(a, n)
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
@@ -95,12 +95,12 @@ proc useVar(a: PEffects, n: PNode) =
if s.id notin a.init:
if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
when true:
Message(n.info, warnProveInit, s.name.s)
message(n.info, warnProveInit, s.name.s)
else:
Message(n.info, errGenerated,
"'$1' might not have been initialized" % s.name.s)
else:
Message(n.info, warnUninit, s.name.s)
message(n.info, warnUninit, s.name.s)
# prevent superfluous warnings about the same variable:
a.init.add s.id
@@ -162,8 +162,8 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) =
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
proc listEffects(a: PEffects) =
for e in items(a.exc): Message(e.info, hintUser, typeToString(e.typ))
for e in items(a.tags): Message(e.info, hintUser, typeToString(e.typ))
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
proc catches(tracked: PEffects, e: PType) =
let e = skipTypes(e, skipPtrs)
@@ -305,21 +305,21 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
if n.kind == nkAddr:
# addr(x[]) can't be proven, but addr(x) can:
if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
elif n.kind == nkSym and n.sym.kind in RoutineKinds:
elif n.kind == nkSym and n.sym.kind in routineKinds:
# 'p' is not nil obviously:
return
case impliesNotNil(tracked.guards, n)
of impUnknown:
Message(n.info, errGenerated,
message(n.info, errGenerated,
"cannot prove '$1' is not nil" % n.renderTree)
of impNo:
Message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
of impYes: discard
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
let op = n.typ
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
InternalAssert op.n.sons[0].kind == nkEffectList
internalAssert op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
let s = n.skipConv
if s.kind == nkSym and s.sym.kind in routineKinds:
@@ -367,7 +367,7 @@ proc trackCase(tracked: PEffects, n: PNode) =
for i in oldState.. <tracked.init.len:
addToIntersection(inter, tracked.init[i])
let exh = case skipTypes(n.sons[0].Typ, abstractVarRange-{tyTypeDesc}).Kind
let exh = case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
of tyFloat..tyFloat128, tyString:
lastSon(n).kind == nkElse
else:
@@ -466,8 +466,7 @@ proc track(tracked: PEffects, n: PNode) =
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize,
mNewSeq, mShallowCopy}:
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
# may not look like an assignment, but it is:
initVarViaNew(tracked, n.sons[1])
for i in 0 .. <safeLen(n):
@@ -477,7 +476,6 @@ proc track(tracked: PEffects, n: PNode) =
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
of nkTryStmt: trackTryStmt(tracked, n)
of nkPragma: trackPragmaStmt(tracked, n)
of nkMacroDef, nkTemplateDef: discard
of nkAsgn, nkFastAsgn:
track(tracked, n.sons[1])
initVar(tracked, n.sons[0])
@@ -527,7 +525,9 @@ proc track(tracked: PEffects, n: PNode) =
if sfDiscriminant in x.sons[0].sym.flags:
addDiscriminantFact(tracked.guards, x)
setLen(tracked.guards, oldFacts)
of nkTypeSection: discard
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef:
discard
else:
for i in 0 .. <safeLen(n): track(tracked, n.sons[i])
@@ -549,7 +549,7 @@ proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool) =
if hints:
for s in 0 .. <spec.len:
if not used.contains(s):
Message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
proc checkMethodEffects*(disp, branch: PSym) =
## checks for consistent effects for multi methods.
@@ -568,42 +568,46 @@ proc checkMethodEffects*(disp, branch: PSym) =
proc setEffectsForProcType*(t: PType, n: PNode) =
var effects = t.n.sons[0]
InternalAssert t.kind == tyProc and effects.kind == nkEffectList
internalAssert t.kind == tyProc and effects.kind == nkEffectList
let
raisesSpec = effectSpec(n, wRaises)
tagsSpec = effectSpec(n, wTags)
if not isNil(raisesSpec) or not isNil(tagsSpec):
InternalAssert effects.len == 0
internalAssert effects.len == 0
newSeq(effects.sons, effectListLen)
if not isNil(raisesSpec):
effects.sons[exceptionEffects] = raisesSpec
if not isNil(tagsSpec):
effects.sons[tagEffects] = tagsSpec
proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0]
InternalAssert effects.kind == nkEffectList
# effects already computed?
if sfForward in s.flags: return
if effects.len == effectListLen: return
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, body.info)
effects.sons[tagEffects] = newNodeI(nkArgList, body.info)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
var t: TEffects
t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects]
t.owner = s
t.init = @[]
t.guards = @[]
proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0]
internalAssert effects.kind == nkEffectList
# effects already computed?
if sfForward in s.flags: return
if effects.len == effectListLen: return
var t: TEffects
initEffects(effects, s, t)
track(t, body)
if not isEmptyType(s.typ.sons[0]) and tfNeedsInit in s.typ.sons[0].flags and
s.kind in {skProc, skConverter, skMethod}:
var res = s.ast.sons[resultPos].sym # get result symbol
if res.id notin t.init:
Message(body.info, warnProveInit, "result")
message(body.info, warnProveInit, "result")
let p = s.ast.sons[pragmasPos]
let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):
@@ -618,4 +622,13 @@ proc trackProc*(s: PSym, body: PNode) =
hints=off)
# after the check, use the formal spec:
effects.sons[tagEffects] = tagsSpec
proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
return
var effects = newNode(nkEffectList, n.info)
var t: TEffects
initEffects(effects, module, t)
track(t, n)

View File

@@ -10,11 +10,8 @@
## this module does the semantic checking of statements
# included from sem.nim
var EnforceVoidContext = PType(kind: tyStmt)
var enforceVoidContext = PType(kind: tyStmt)
proc semCommand(c: PContext, n: PNode): PNode =
result = semExprNoType(c, n)
proc semDiscard(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1)
@@ -58,10 +55,10 @@ proc semWhile(c: PContext, n: PNode): PNode =
n.sons[1] = semStmt(c, n.sons[1])
dec(c.p.nestedLoopCounter)
closeScope(c)
if n.sons[1].typ == EnforceVoidContext:
result.typ = EnforceVoidContext
if n.sons[1].typ == enforceVoidContext:
result.typ = enforceVoidContext
proc toCover(t: PType): biggestInt =
proc toCover(t: PType): BiggestInt =
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n)
@@ -70,14 +67,14 @@ proc toCover(t: PType): biggestInt =
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
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)
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}:
if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skConverter,
skIterator, skClosureIterator}:
performProcvarCheck(c, n, n.sym)
proc semProc(c: PContext, n: PNode): PNode
@@ -86,8 +83,8 @@ include semdestruct
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,
if instantiateDestructor(c, n.typ) != nil:
localError(n.info, errGenerated,
"usage of a type with a destructor in a non destructible context")
# This still breaks too many things:
when false:
@@ -117,7 +114,7 @@ const
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr}
proc ImplicitlyDiscardable(n: PNode): bool =
proc implicitlyDiscardable(n: PNode): bool =
var n = n
while n.kind in skipForDiscardable: n = n.lastSon
result = isCallExpr(n) and n.sons[0].kind == nkSym and
@@ -126,37 +123,36 @@ proc ImplicitlyDiscardable(n: PNode): bool =
proc fixNilType(n: PNode) =
if isAtom(n):
if n.kind != nkNilLit and n.typ != nil:
localError(n.info, errDiscardValue)
localError(n.info, errDiscardValueX, n.typ.typeToString)
elif n.kind in {nkStmtList, nkStmtListExpr}:
n.kind = nkStmtList
for it in n: fixNilType(it)
n.typ = nil
proc discardCheck(c: PContext, result: PNode) =
if c.inTypeClass > 0: return
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
if result.kind == nkNilLit:
result.typ = nil
elif ImplicitlyDiscardable(result):
message(result.info, warnNilStatement)
elif implicitlyDiscardable(result):
var n = result
result.typ = nil
while n.kind in skipForDiscardable:
n = n.lastSon
n.typ = nil
elif c.InTypeClass > 0 and result.typ.kind == tyBool:
let verdict = semConstExpr(c, result)
if verdict.intVal == 0:
localError(result.info, "type class predicate failed.")
elif result.typ.kind != tyError and gCmd != cmdInteractive:
if result.typ.kind == tyNil:
fixNilType(result)
message(result.info, warnNilStatement)
else:
var n = result
while n.kind in skipForDiscardable: n = n.lastSon
localError(n.info, errDiscardValue)
localError(n.info, errDiscardValueX, result.typ.typeToString)
proc semIf(c: PContext, n: PNode): PNode =
result = n
var typ = CommonTypeBegin
var typ = commonTypeBegin
var hasElse = false
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
@@ -176,7 +172,7 @@ proc semIf(c: PContext, n: PNode): PNode =
for it in n: discardCheck(c, it.lastSon)
result.kind = nkIfStmt
# propagate any enforced VoidContext:
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
if typ == enforceVoidContext: result.typ = enforceVoidContext
else:
for it in n:
let j = it.len-1
@@ -190,16 +186,16 @@ proc semCase(c: PContext, n: PNode): PNode =
openScope(c)
n.sons[0] = semExprWithType(c, n.sons[0])
var chckCovered = false
var covered: biggestint = 0
var typ = CommonTypeBegin
var covered: BiggestInt = 0
var typ = commonTypeBegin
var hasElse = false
case skipTypes(n.sons[0].Typ, abstractVarRange-{tyTypeDesc}).Kind
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32:
chckCovered = true
of tyFloat..tyFloat128, tyString, tyError:
nil
discard
else:
LocalError(n.info, errSelectorMustBeOfCertainTypes)
localError(n.info, errSelectorMustBeOfCertainTypes)
return
for i in countup(1, sonsLen(n) - 1):
var x = n.sons[i]
@@ -236,8 +232,8 @@ proc semCase(c: PContext, n: PNode): PNode =
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
# propagate any enforced VoidContext:
if typ == EnforceVoidContext:
result.typ = EnforceVoidContext
if typ == enforceVoidContext:
result.typ = enforceVoidContext
else:
for i in 1..n.len-1:
var it = n.sons[i]
@@ -249,7 +245,7 @@ proc semTry(c: PContext, n: PNode): PNode =
result = n
inc c.p.inTryStmt
checkMinSonsLen(n, 2)
var typ = CommonTypeBegin
var typ = commonTypeBegin
n.sons[0] = semExprBranchScope(c, n.sons[0])
typ = commonType(typ, n.sons[0].typ)
var check = initIntSet()
@@ -267,10 +263,10 @@ proc semTry(c: PContext, n: PNode): PNode =
var typ = semTypeNode(c, a.sons[j], nil)
if typ.kind == tyRef: typ = typ.sons[0]
if typ.kind != tyObject:
LocalError(a.sons[j].info, errExprCannotBeRaised)
localError(a.sons[j].info, errExprCannotBeRaised)
a.sons[j] = newNodeI(nkType, a.sons[j].info)
a.sons[j].typ = typ
if ContainsOrIncl(check, typ.id):
if containsOrIncl(check, typ.id):
localError(a.sons[j].info, errExceptionAlreadyHandled)
elif a.kind != nkFinally:
illFormedAst(n)
@@ -281,8 +277,8 @@ proc semTry(c: PContext, n: PNode): PNode =
if isEmptyType(typ) or typ.kind == tyNil:
discardCheck(c, n.sons[0])
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
if typ == EnforceVoidContext:
result.typ = EnforceVoidContext
if typ == enforceVoidContext:
result.typ = enforceVoidContext
else:
n.sons[0] = fitNode(c, typ, n.sons[0])
for i in 1..n.len-1:
@@ -291,7 +287,7 @@ proc semTry(c: PContext, n: PNode): PNode =
it.sons[j] = fitNode(c, typ, it.sons[j])
result.typ = typ
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ, check=true)
@@ -302,7 +298,7 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
proc findShadowedVar(c: PContext, v: PSym): PSym =
for scope in walkScopes(c.currentScope.parent):
if scope == c.topLevelScope: break
let shadowed = StrTableGet(scope.symbols, v.name)
let shadowed = strTableGet(scope.symbols, v.name)
if shadowed != nil and shadowed.kind in skLocalVars:
return shadowed
@@ -322,18 +318,19 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
proc checkNilable(v: PSym) =
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
if v.ast.isNil:
Message(v.info, warnProveInit, v.name.s)
message(v.info, warnProveInit, v.name.s)
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
Message(v.info, warnProveInit, v.name.s)
message(v.info, warnProveInit, v.name.s)
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
var hasCompileTime = false
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: IllFormedAst(a)
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
checkMinSonsLen(a, 3)
var length = sonsLen(a)
var typ: PType
@@ -347,15 +344,20 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# BUGFIX: ``fitNode`` is needed here!
# check type compability between def.typ and typ:
if typ != nil: def = fitNode(c, typ, def)
else: typ = skipIntLit(def.typ)
else:
typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and
typ.lastSon.kind == tyEmpty:
localError(def.info, errCannotInferTypeOfTheLiteral,
($typ.kind).substr(2).toLower)
else:
def = ast.emptyNode
if symkind == skLet: LocalError(a.info, errLetNeedsInit)
if symkind == skLet: localError(a.info, errLetNeedsInit)
# this can only happen for errornous var statements:
if typ == nil: continue
if not typeAllowed(typ, symkind):
LocalError(a.info, errXisNoType, typeToString(typ))
localError(a.info, errXisNoType, typeToString(typ))
var tup = skipTypes(typ, {tyGenericInst})
if a.kind == nkVarTuple:
if tup.kind != tyTuple:
@@ -370,12 +372,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addSon(result, b)
elif tup.kind == tyTuple and def.kind == nkPar and
a.kind == nkIdentDefs and a.len > 3:
Message(a.info, warnEachIdentIsTuple)
message(a.info, warnEachIdentIsTuple)
for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], symkind)
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
when oKeepVariableNames:
if c.InUnrolledContext > 0: v.flags.incl(sfShadowed)
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
let shadowed = findShadowedVar(c, v)
if shadowed != nil:
@@ -383,12 +385,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# a shadowed variable is an error unless it appears on the right
# side of the '=':
if warnShadowIdent in gNotes and not identWithin(def, v.name):
Message(a.info, warnShadowIdent, v.name.s)
message(a.info, warnShadowIdent, v.name.s)
if a.kind != nkVarTuple:
if def != nil and def.kind != nkEmpty:
# this is needed for the evaluation pass and for the guard checking:
v.ast = def
if sfThread in v.flags: LocalError(def.info, errThreadvarCannotInit)
if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
v.typ = typ
b = newNodeI(nkIdentDefs, a.info)
if importantComments():
@@ -403,14 +405,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
v.typ = tup.sons[j]
b.sons[j] = newSymNode(v)
checkNilable(v)
if sfCompileTime in v.flags: hasCompileTime = true
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n)
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): IllFormedAst(a)
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
var v = semIdentDef(c, a.sons[0], skConst)
var typ: PType = nil
@@ -418,16 +422,18 @@ proc semConst(c: PContext, n: PNode): PNode =
var def = semConstExpr(c, a.sons[2])
if def == nil:
LocalError(a.sons[2].info, errConstExprExpected)
localError(a.sons[2].info, errConstExprExpected)
continue
# check type compatibility between def.typ and typ:
if typ != nil:
def = fitRemoveHiddenConv(c, typ, def)
else:
typ = def.typ
if typ == nil: continue
if typ == nil:
localError(a.sons[2].info, errConstExprExpected)
continue
if not typeAllowed(typ, skConst):
LocalError(a.info, errXisNoType, typeToString(typ))
localError(a.info, errXisNoType, typeToString(typ))
continue
v.typ = typ
v.ast = def # no need to copy
@@ -494,17 +500,17 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.InUnrolledContext
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(SemStmt(c.c, body))
dec c.c.InUnrolledContext
father.add(semStmt(c.c, body))
dec c.c.inUnrolledContext
closeScope(c.c)
of nkNilLit: nil
of nkNilLit: discard
of nkRecCase:
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
LocalError(forLoop.info, errGenerated,
localError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
@@ -533,9 +539,9 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
if trueSymbol == nil:
LocalError(n.info, errSystemNeeds, "true")
localError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool)
@@ -546,7 +552,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var length = sonsLen(n)
var call = n.sons[length-2]
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
LocalError(n.info, errWrongNumberOfVariables)
localError(n.info, errWrongNumberOfVariables)
return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
@@ -555,10 +561,10 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
return result
for i in 1..call.len-1:
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)
Inc(c.p.nestedLoopCounter)
inc(c.p.nestedLoopCounter)
if tupleTypeA.kind == tyTuple:
var loopBody = n.sons[length-1]
for i in 0..sonsLen(tupleTypeA)-1:
@@ -568,16 +574,16 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
fc.tupleIndex = i
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.InUnrolledContext
stmts.add(SemStmt(c, body))
dec c.InUnrolledContext
inc c.inUnrolledContext
stmts.add(semStmt(c, body))
dec c.inUnrolledContext
closeScope(c)
else:
var fc: TFieldsCtx
fc.m = m
fc.c = c
semForObjectFields(fc, tupleTypeA.n, n, stmts)
Dec(c.p.nestedLoopCounter)
dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so
# we avoid it now if we can:
if hasSonWith(stmts, nkBreakStmt):
@@ -593,7 +599,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
if shadowed != nil:
# XXX should we do this here?
#shadowed.flags.incl(sfShadowed)
Message(v.info, warnShadowIdent, v.name.s)
message(v.info, warnShadowIdent, v.name.s)
addDecl(c, v)
proc symForVar(c: PContext, n: PNode): PSym =
@@ -603,7 +609,8 @@ proc symForVar(c: PContext, n: PNode): PSym =
proc semForVars(c: PContext, n: PNode): PNode =
result = n
var length = sonsLen(n)
var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst})
let iterBase = n.sons[length-2].typ.skipTypes({tyIter})
var iter = skipTypes(iterBase, {tyGenericInst})
# length == 3 means that there is one for loop variable
# and thus no tuple unpacking:
if iter.kind != tyTuple or length == 3:
@@ -613,13 +620,13 @@ proc semForVars(c: PContext, n: PNode): PNode =
# BUGFIX: don't use `iter` here as that would strip away
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
# for an example:
v.typ = n.sons[length-2].typ
v.typ = iterBase
n.sons[0] = newSymNode(v)
if sfGenSym notin v.flags: addForVarDecl(c, v)
else:
LocalError(n.info, errWrongNumberOfVariables)
localError(n.info, errWrongNumberOfVariables)
elif length-2 != sonsLen(iter):
LocalError(n.info, errWrongNumberOfVariables)
localError(n.info, errWrongNumberOfVariables)
else:
for i in countup(0, length - 3):
var v = symForVar(c, n.sons[i])
@@ -627,9 +634,9 @@ proc semForVars(c: PContext, n: PNode): PNode =
v.typ = iter.sons[i]
n.sons[i] = newSymNode(v)
if sfGenSym notin v.flags: addForVarDecl(c, v)
Inc(c.p.nestedLoopCounter)
n.sons[length-1] = SemStmt(c, n.sons[length-1])
Dec(c.p.nestedLoopCounter)
inc(c.p.nestedLoopCounter)
n.sons[length-1] = semStmt(c, n.sons[length-1])
dec(c.p.nestedLoopCounter)
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
result = newNodeI(nkCall, arg.info)
@@ -647,29 +654,31 @@ proc semFor(c: PContext, n: PNode): PNode =
openScope(c)
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
var call = n.sons[length-2]
if call.kind in nkCallKinds and call.sons[0].typ.callConv == ccClosure:
# first class iterator:
result = semForVars(c, n)
elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator:
if length == 3:
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
elif length == 4:
n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
else:
LocalError(n.sons[length-2].info, errIteratorExpected)
result = semForVars(c, n)
elif call.sons[0].sym.magic != mNone:
let isCallExpr = call.kind in nkCallKinds
if isCallExpr and call.sons[0].sym.magic != mNone:
if call.sons[0].sym.magic == mOmpParFor:
result = semForVars(c, n)
result.kind = nkParForStmt
else:
result = semForFields(c, n, call.sons[0].sym.magic)
elif (isCallExpr and call.sons[0].typ.callConv == ccClosure) or
call.typ.kind == tyIter:
# first class iterator:
result = semForVars(c, n)
elif not isCallExpr or call.sons[0].kind != nkSym or
call.sons[0].sym.kind notin skIterators:
if length == 3:
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
elif length == 4:
n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
else:
localError(n.sons[length-2].info, errIteratorExpected)
result = semForVars(c, n)
else:
result = semForVars(c, n)
# propagate any enforced VoidContext:
if n.sons[length-1].typ == EnforceVoidContext:
result.typ = EnforceVoidContext
if n.sons[length-1].typ == enforceVoidContext:
result.typ = enforceVoidContext
closeScope(c)
proc semRaise(c: PContext, n: PNode): PNode =
@@ -695,7 +704,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue
if a.kind != nkTypeDef: IllFormedAst(a)
if a.kind != nkTypeDef: illFormedAst(a)
checkSonsLen(a, 3)
var s = semIdentDef(c, a.sons[0], skType)
s.typ = newTypeS(tyForward, c)
@@ -710,12 +719,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.sons[0].kind != nkSym): IllFormedAst(a)
if (a.sons[0].kind != nkSym): illFormedAst(a)
var s = a.sons[0].sym
if s.magic == mNone and a.sons[2].kind == nkEmpty:
LocalError(a.info, errImplOfXexpected, s.name.s)
localError(a.info, errImplOfXexpected, s.name.s)
if s.magic != mNone: processMagicType(c, s)
if a.sons[1].kind != nkEmpty:
# We have a generic type declaration here. In generic types,
@@ -736,19 +745,15 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# we fill it out later. For magic generics like 'seq', it won't be filled
# so we use tyEmpty instead of nil to not crash for strange conversions
# like: mydata.seq
rawAddSon(s.typ, newTypeS(tyEmpty, c))
rawAddSon(s.typ, newTypeS(tyNone, c))
s.ast = a
when oUseLateInstantiation:
var body: PType = nil
s.typScope = c.currentScope.parent
else:
inc c.InGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.InGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
inc c.inGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.inGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
popOwner()
closeScope(c)
elif a.sons[2].kind != nkEmpty:
@@ -764,11 +769,34 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
s.ast = a
popOwner()
proc checkForMetaFields(n: PNode) =
template checkMeta(t) =
if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
localError(n.info, errTIsNotAConcreteType, t.typeToString)
case n.kind
of nkRecList, nkRecCase:
for s in n: checkForMetaFields(s)
of nkOfBranch, nkElse:
checkForMetaFields(n.lastSon)
of nkSym:
let t = n.sym.typ
case t.kind
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
tyProc, tyGenericInvokation, tyGenericInst:
let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
for i in start .. <t.sons.len:
checkMeta(t.sons[i])
else:
checkMeta(t)
else:
internalAssert false
proc typeSectionFinalPass(c: PContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: IllFormedAst(a)
if a.sons[0].kind != nkSym: illFormedAst(a)
var s = a.sons[0].sym
# compute the type's size and check for illegal recursions:
if a.sons[1].kind == nkEmpty:
@@ -780,18 +808,20 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
if s.typ.kind in {tyObject, tyTuple}:
checkForMetaFields(s.typ.n)
let aa = a.sons[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
aa.sons[0].kind == nkObjectTy:
# give anonymous object a dummy symbol:
var st = s.typ
if st.kind == tyGenericBody: st = st.lastSon
InternalAssert st.kind in {tyPtr, tyRef}
InternalAssert st.sons[0].sym == nil
st.sons[0].sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
internalAssert st.kind in {tyPtr, tyRef}
internalAssert st.lastSon.sym == nil
st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
getCurrOwner(), s.info)
proc SemTypeSection(c: PContext, n: PNode): PNode =
proc semTypeSection(c: PContext, n: PNode): PNode =
typeSectionLeftSidePass(c, n)
typeSectionRightSidePass(c, n)
typeSectionFinalPass(c, n)
@@ -810,12 +840,12 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) =
proc semBorrow(c: PContext, n: PNode, s: PSym) =
# search for the correct alias:
var b = SearchForBorrowProc(c, c.currentScope.parent, s)
var b = searchForBorrowProc(c, c.currentScope.parent, s)
if b != nil:
# store the alias:
n.sons[bodyPos] = newSymNode(b)
else:
LocalError(n.info, errNoSymbolToBorrowFromFound)
localError(n.info, errNoSymbolToBorrowFromFound)
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
if t != nil:
@@ -853,7 +883,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
prc.sons[namePos] = newIdentNode(idDelegator, prc.info)
prc.sons[pragmasPos] = copyExcept(n, i)
else:
LocalError(prc.info, errOnlyACallOpCanBeDelegator)
localError(prc.info, errOnlyACallOpCanBeDelegator)
continue
# we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
# let the semantic checker deal with it:
@@ -868,6 +898,8 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
return semStmt(c, x)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda
result = semProcAnnotation(c, n)
if result != nil: return result
result = n
@@ -881,12 +913,19 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
s = n[namePos].sym
pushOwner(s)
openScope(c)
if n.sons[genericParamsPos].kind != nkEmpty:
illFormedAst(n) # process parameters:
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
gp = n.sons[genericParamsPos]
else:
gp = newNodeI(nkGenericParams, n.info)
if n.sons[paramsPos].kind != nkEmpty:
var gp = newNodeI(nkGenericParams, n.info)
semParamList(c, n.sons[ParamsPos], gp, s)
ParamsTypeCheck(c, s.typ)
semParamList(c, n.sons[paramsPos], gp, s)
# paramsTypeCheck(c, s.typ)
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
n.sons[genericParamsPos] = gp
else:
s.typ = newTypeS(tyProc, c)
rawAddSon(s.typ, nil)
@@ -895,22 +934,53 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
s.options = gOptions
if n.sons[bodyPos].kind != nkEmpty:
if sfImportc in s.flags:
LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
#if efDetermineType notin flags:
# XXX not good enough; see tnamedparamanonproc.nim
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
elif efOperand notin flags:
localError(n.info, errGenericLambdaNotAllowed)
sideEffectsCheck(c, s)
else:
LocalError(n.info, errImplOfXexpected, s.name.s)
localError(n.info, errImplOfXexpected, s.name.s)
closeScope(c) # close scope for parameters
popOwner()
result.typ = s.typ
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n
n = replaceTypesInBody(c, pt, n)
result = n
n.sons[genericParamsPos] = emptyNode
n.sons[paramsPos] = n.typ.n
openScope(c)
var s = n.sons[namePos].sym
addParams(c, n.typ.n, skProc)
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
addResultNode(c, n)
popProcCon(c)
closeScope(c)
s.ast = result
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
# result = inferred.ast
# result.kind = arg.kind
proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned.
@@ -922,11 +992,10 @@ proc activate(c: PContext, n: PNode) =
of nkCallKinds:
for i in 1 .. <n.len: activate(c, n[i])
else:
nil
discard
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
if s.typ.sons[0] != nil and
(s.kind != skIterator or s.typ.callConv == ccClosure):
if s.typ.sons[0] != nil and s.kind != skIterator:
addResult(c, s.typ.sons[0], n.info, s.kind)
addResultNode(c, n)
@@ -937,7 +1006,7 @@ type
stepCompileBody
proc isForwardDecl(s: PSym): bool =
InternalAssert s.kind == skProc
internalAssert s.kind == skProc
result = s.ast[bodyPos].kind != nkEmpty
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
@@ -949,9 +1018,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
checkSonsLen(n, bodyPos + 1)
var s: PSym
var typeIsDetermined = false
var isAnon = false
if n[namePos].kind != nkSym:
assert phase == stepRegisterSymbol
s = semIdentDef(c, n.sons[0], kind)
if n[namePos].kind == nkEmpty:
s = newSym(kind, idAnon, getCurrOwner(), n.info)
isAnon = true
else:
s = semIdentDef(c, n.sons[0], kind)
n.sons[namePos] = newSymNode(s)
s.ast = n
s.scope = c.currentScope
@@ -963,7 +1038,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
return
else:
s = n[namePos].sym
s.owner = getCurrOwner()
typeIsDetermined = s.typ == nil
s.ast = n
s.scope = c.currentScope
# if typeIsDetermined: assert phase == stepCompileBody
# else: assert phase == stepDetermineType
# before compiling the proc body, set as current the scope
@@ -980,7 +1059,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
gp = newNodeI(nkGenericParams, n.info)
# process parameters:
if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[ParamsPos], gp, s)
semParamList(c, n.sons[paramsPos], gp, s)
if sonsLen(gp) > 0:
if n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
@@ -992,13 +1071,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
rawAddSon(s.typ, nil)
if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
if s.kind == skIterator: s.typ.flags.incl(tfIterator)
if s.kind in skIterators:
s.typ.flags.incl(tfIterator)
var proto = SearchForProc(c, s.scope, s)
if proto == nil:
s.typ.callConv = lastOptionEntry(c).defaultCC
var proto = searchForProc(c, s.scope, s)
if proto == nil:
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC
# add it here, so that recursive procs are possible:
if sfGenSym in s.flags: nil
if sfGenSym in s.flags: discard
elif kind in OverloadableSyms:
if not typeIsDetermined:
addInterfaceOverloadableSymAt(c, s.scope, s)
@@ -1008,12 +1089,12 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], validPragmas)
else:
implictPragmas(c, s, n, validPragmas)
implicitPragmas(c, s, n, validPragmas)
else:
if n.sons[pragmasPos].kind != nkEmpty:
LocalError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
if sfForward notin proto.flags:
WrongRedefinition(n.info, proto.name.s)
wrongRedefinition(n.info, proto.name.s)
excl(proto.flags, sfForward)
closeScope(c) # close scope with wrong parameter symbols
openScope(c) # open scope for old (correct) parameter symbols
@@ -1026,7 +1107,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
n.sons[paramsPos] = proto.ast.sons[paramsPos]
n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
if n.sons[namePos].kind != nkSym: internalError(n.info, "semProcAux")
n.sons[namePos].sym = proto
if importantComments() and not isNil(proto.ast.comment):
n.comment = proto.ast.comment
@@ -1035,12 +1116,16 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pushOwner(s)
s.options = gOptions
if sfDestructor in s.flags: doDestructorStuff(c, s, n)
if n.sons[bodyPos].kind != nkEmpty:
if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags:
LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
if n.sons[genericParamsPos].kind == nkEmpty:
ParamsTypeCheck(c, s.typ)
if sfBorrow in s.flags:
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
let usePseudoGenerics = kind in {skMacro, skTemplate}
# Macros and Templates can have generic parameters, but they are
# only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now)
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
pushProcCon(c, s)
maybeAddResult(c, s, n)
if sfImportc notin s.flags:
@@ -1050,17 +1135,17 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c)
else:
if s.typ.sons[0] != nil and kind != skIterator:
else:
if s.typ.sons[0] != nil and kind notin skIterators:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
var toBind = initIntSet()
n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
fixupInstantiatedSymbols(c, s)
if sfImportc in s.flags:
if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode
else:
if proto != nil: LocalError(n.info, errImplOfXexpected, proto.name.s)
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
incl(s.flags, sfForward)
elif sfBorrow in s.flags: semBorrow(c, n, s)
@@ -1070,6 +1155,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner()
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
if isAnon: result.typ = s.typ
proc determineType(c: PContext, s: PSym) =
if s.typ != nil: return
@@ -1077,11 +1163,19 @@ proc determineType(c: PContext, s: PSym) =
discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
proc semIterator(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skIterator, iteratorPragmas)
let kind = if hasPragma(n[pragmasPos], wClosure) or
n[namePos].kind == nkEmpty: skClosureIterator
else: skIterator
# gensym'ed iterator?
if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner()
n[namePos].sym.kind = kind
result = semProcAux(c, n, kind, iteratorPragmas)
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil and s.typ.callConv != ccClosure:
LocalError(n.info, errXNeedsReturnType, "iterator")
localError(n.info, errXNeedsReturnType, "iterator")
# iterators are either 'inline' or 'closure'; for backwards compatibility,
# we require first class iterators to be marked with 'closure' explicitly
# -- at least for 0.9.2.
@@ -1095,7 +1189,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
# and they always at least use the 'env' for the state field:
incl(s.typ.flags, tfCapturesEnv)
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
LocalError(n.info, errImplOfXexpected, s.name.s)
localError(n.info, errImplOfXexpected, s.name.s)
proc semProc(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skProc, procPragmas)
@@ -1146,11 +1240,11 @@ proc evalInclude(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var f = checkModuleName(n.sons[i])
if f != InvalidFileIDX:
if ContainsOrIncl(c.includedFiles, f):
LocalError(n.info, errRecursiveDependencyX, f.toFilename)
if containsOrIncl(c.includedFiles, f):
localError(n.info, errRecursiveDependencyX, f.toFilename)
else:
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
Excl(c.includedFiles, f)
excl(c.includedFiles, f)
proc setLine(n: PNode, info: TLineInfo) =
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
@@ -1159,20 +1253,25 @@ proc setLine(n: PNode, info: TLineInfo) =
proc semPragmaBlock(c: PContext, n: PNode): PNode =
let pragmaList = n.sons[0]
pragma(c, nil, pragmaList, exprPragmas)
result = semStmt(c, n.sons[1])
result = semExpr(c, n.sons[1])
for i in 0 .. <pragmaList.len:
if whichPragma(pragmaList.sons[i]) == wLine:
setLine(result, pragmaList.sons[i].info)
proc semStaticStmt(c: PContext, n: PNode): PNode =
let a = semStmt(c, n.sons[0])
result = evalStaticExpr(c, c.module, a, c.p.owner)
if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
result = emptyNode
elif result.kind == nkEmpty:
result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = emptyNode
n.sons[0] = a
evalStaticStmt(c.module, a, c.p.owner)
result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = emptyNode
when false:
result = evalStaticStmt(c.module, a, c.p.owner)
if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
result = emptyNode
elif result.kind == nkEmpty:
result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = emptyNode
proc usesResult(n: PNode): bool =
# nkStmtList(expr) properly propagates the void context,
@@ -1186,7 +1285,7 @@ proc usesResult(n: PNode): bool =
for c in n:
if usesResult(c): return true
proc semStmtList(c: PContext, n: PNode): PNode =
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# these must be last statements in a block:
const
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@@ -1224,30 +1323,36 @@ proc semStmtList(c: PContext, n: PNode): PNode =
return
else:
n.sons[i] = semExpr(c, n.sons[i])
if n.sons[i].typ == EnforceVoidContext or usesResult(n.sons[i]):
if c.inTypeClass > 0 and n[i].typ != nil and n[i].typ.kind == tyBool:
let verdict = semConstExpr(c, n[i])
if verdict.intVal == 0:
localError(result.info, "type class predicate failed")
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
voidContext = true
n.typ = EnforceVoidContext
if i != last or voidContext:
n.typ = enforceVoidContext
if i == last and (length == 1 or efWantValue in flags):
n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
elif i != last or voidContext:
discardCheck(c, n.sons[i])
else:
n.typ = n.sons[i].typ
if not isEmptyType(n.typ):
n.kind = nkStmtListExpr
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
case n.sons[i].kind
of nkVarSection, nkLetSection:
let (outer, inner) = insertDestructors(c, n.sons[i])
if outer != nil:
n.sons[i] = outer
for j in countup(i+1, length-1):
inner.addSon(SemStmt(c, n.sons[j]))
var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
inner.addSon(semStmtList(c, rest, flags))
n.sons.setLen(i+1)
return
of LastBlockStmts:
for j in countup(i + 1, length - 1):
case n.sons[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
else: nil
else: discard
if result.len == 1:
result = result.sons[0]
when false:
@@ -1260,7 +1365,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
# "Last expression must be explicitly returned if it " &
# "is discardable or discarded")
proc SemStmt(c: PContext, n: PNode): PNode =
proc semStmt(c: PContext, n: PNode): PNode =
# now: simply an alias:
result = semExprNoType(c, n)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -14,7 +14,7 @@ discard """
template `||` (a, b: expr): expr =
let aa = a
(if aa: aa else: b)
if aa: aa else: b
var
a, b: T
@@ -36,9 +36,9 @@ proc symBinding(n: PNode): TSymBinding =
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
if key.kind == nkIdent:
case whichKeyword(key.ident)
of wGenSym: return spGenSym
of wGensym: return spGenSym
of wInject: return spInject
else: nil
else: discard
type
TSymChoiceRule = enum
@@ -79,7 +79,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
# the same symbol!
# This is however not true anymore for hygienic templates as semantic
# processing for them changes the symbol table...
let s = QualifiedLookUp(c, a)
let s = qualifiedLookUp(c, a)
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, n, s, scClosed)
@@ -106,7 +106,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
type
TemplCtx {.pure, final.} = object
c: PContext
toBind, toMixin: TIntSet
toBind, toMixin, toInject: TIntSet
owner: PSym
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
@@ -115,7 +115,7 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
of nkIdent:
result = n
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
@@ -138,6 +138,18 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
result = semTemplBody(c, n)
closeScope(c)
proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
else:
for i in 0 .. <n.safeLen:
result.sons[i] = onlyReplaceParams(c, n.sons[i])
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerAcc(n), c.owner, n.info)
incl(result.flags, sfGenSym)
@@ -145,7 +157,28 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym':
if n.kind != nkPragmaExpr or symBinding(n.sons[1]) != spInject:
if n.kind == nkPragmaExpr and symBinding(n.sons[1]) == spInject:
# even if injected, don't produce a sym choice here:
#n = semTemplBody(c, n)
var x = n[0]
while true:
case x.kind
of nkPostfix: x = x[1]
of nkPragmaExpr: x = x[0]
of nkIdent: break
of nkAccQuoted:
# consider: type `T TemplParam` {.inject.}
# it suffices to return to treat it like 'inject':
n = onlyReplaceParams(c, n)
return
else:
illFormedAst(x)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(n, ident)
else:
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
let local = newGenSym(k, ident, c)
@@ -153,8 +186,37 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
replaceIdentBySym(n, newSymNode(local, n.info))
else:
replaceIdentBySym(n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed)
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of OverloadableSyms:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
result = newSymNodeTypeDesc(s, n.info)
of skParam:
result = n
of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNodeTypeDesc(s, n.info)
else:
result = n
else: result = newSymNode(s, n.info)
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
else:
n = semTemplBody(c, n)
for i in countup(0, safeLen(n) - 1):
result.sons[i] = semRoutineInTemplName(c, n.sons[i])
proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
result = n
@@ -170,17 +232,17 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
else:
n.sons[namePos] = ident
else:
n.sons[namePos] = semTemplBody(c, n.sons[namePos])
n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
openScope(c)
for i in patternPos..bodyPos:
n.sons[i] = semTemplBody(c, n.sons[i])
closeScope(c)
proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind) =
for i in countup(ord(symkind == skConditional), sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semTemplBody(c, a.sons[L-2])
@@ -193,18 +255,23 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = n
case n.kind
of nkIdent:
let s = QualifiedLookUp(c.c, n, {})
if n.ident.id in c.toInject: return n
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
elif contains(c.toMixin, s.name.id):
result = symChoice(c.c, n, s, scForceOpen)
elif s.owner == c.owner and sfGenSym in s.flags:
# template tmp[T](x: var seq[T]) =
# var yz: T
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
else:
result = semTemplSymbol(c.c, n, s)
of nkBind:
result = semTemplBody(c, n.sons[0])
of nkBindStmt:
@@ -212,7 +279,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkMixinStmt:
result = semMixinStmt(c.c, n, c.toMixin)
of nkEmpty, nkSym..nkNilLit:
nil
discard
of nkIfStmt:
for i in countup(0, sonsLen(n)-1):
var it = n.sons[i]
@@ -274,7 +341,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): IllFormedAst(a)
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addLocalDecl(c, a.sons[0], skConst)
a.sons[1] = semTemplBody(c, a.sons[1])
@@ -283,13 +350,13 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addLocalDecl(c, a.sons[0], skType)
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty:
openScope(c)
@@ -303,21 +370,33 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkMethodDef:
result = semRoutineInTemplBody(c, n, skMethod)
of nkIteratorDef:
result = semRoutineInTemplBody(c, n, skIterator)
let kind = if hasPragma(n[pragmasPos], wClosure): skClosureIterator
else: skIterator
result = semRoutineInTemplBody(c, n, kind)
of nkTemplateDef:
result = semRoutineInTemplBody(c, n, skTemplate)
of nkMacroDef:
result = semRoutineInTemplBody(c, n, skMacro)
of nkConverterDef:
result = semRoutineInTemplBody(c, n, skConverter)
of nkPragmaExpr:
result.sons[0] = semTemplBody(c, n.sons[0])
of nkPostfix:
result.sons[1] = semTemplBody(c, n.sons[1])
of nkPragma:
result = onlyReplaceParams(c, n)
else:
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
# so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if Contains(c.toBind, s.id):
if contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
elif contains(c.toMixin, s.name.id):
return symChoice(c.c, n, s, scForceOpen)
else:
return symChoice(c.c, n, s, scOpen)
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semTemplBody(c, n.sons[i])
@@ -326,24 +405,24 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
result = n
case n.kind
of nkIdent:
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
of nkBind:
result = semTemplBodyDirty(c, n.sons[0])
of nkBindStmt:
result = semBindStmt(c.c, n, c.toBind)
of nkEmpty, nkSym..nkNilLit:
nil
discard
else:
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
# so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
if s != nil and Contains(c.toBind, s.id):
let s = qualifiedLookUp(c.c, n, {})
if s != nil and contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
result = n
for i in countup(0, sonsLen(n) - 1):
@@ -358,7 +437,7 @@ proc transformToExpr(n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind
of nkCommentStmt, nkEmpty, nkNilLit:
nil
discard
else:
if realStmt == - 1: realStmt = i
else: realStmt = - 2
@@ -368,7 +447,7 @@ proc transformToExpr(n: PNode): PNode =
n.kind = nkBlockExpr
#nkIfStmt: n.kind = nkIfExpr // this is not correct!
else:
nil
discard
proc semTemplateDef(c: PContext, n: PNode): PNode =
var s: PSym
@@ -378,6 +457,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else:
s = semIdentVis(c, skTemplate, n.sons[0], {})
# check parameter list:
s.scope = c.currentScope
pushOwner(s)
openScope(c)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
@@ -392,7 +472,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
gp = newNodeI(nkGenericParams, n.info)
# process parameters:
if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[ParamsPos], gp, s)
semParamList(c, n.sons[paramsPos], gp, s)
if sonsLen(gp) > 0:
if n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
@@ -413,6 +493,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
var ctx: TemplCtx
ctx.toBind = initIntSet()
ctx.toMixin = initIntSet()
ctx.toInject = initIntSet()
ctx.c = c
ctx.owner = s
if sfDirty in s.flags:
@@ -427,12 +508,12 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s.ast = n
result = n
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)
var proto = SearchForProc(c, c.currentScope, s)
localError(n.info, errImplOfXexpected, s.name.s)
var proto = searchForProc(c, c.currentScope, s)
if proto == nil:
addInterfaceOverloadableSymAt(c, c.currentScope, s)
else:
SymTabReplace(c.currentScope.symbols, proto, s)
symTabReplace(c.currentScope.symbols, proto, s)
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
@@ -455,17 +536,17 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newParam(c, n, s)
elif Contains(c.toBind, s.id):
elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
elif templToExpand(s):
result = semPatternBody(c, semTemplateExpr(c.c, n, s, false))
result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
else:
nil
discard
# we keep the ident unbound for matching instantiated symbols and
# more flexibility
proc expectParam(c: var TemplCtx, n: PNode): PNode =
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
if s != nil and s.owner == c.owner and s.kind == skParam:
result = newParam(c, n, s)
else:
@@ -475,11 +556,11 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
result = n
case n.kind
of nkIdent:
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
result = handleSym(c, n, s)
of nkBindStmt:
result = semBindStmt(c.c, n, c.toBind)
of nkEmpty, nkSym..nkNilLit: nil
of nkEmpty, nkSym..nkNilLit: discard
of nkCurlyExpr:
# we support '(pattern){x}' to bind a subpattern to a parameter 'x';
# '(pattern){|x}' does the same but the matches will be gathered in 'x'
@@ -498,12 +579,12 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
else:
localError(n.info, errInvalidExpression)
of nkCallKinds:
let s = QualifiedLookUp(c.c, n.sons[0], {})
let s = qualifiedLookUp(c.c, n.sons[0], {})
if s != nil:
if s.owner == c.owner and s.kind == skParam: nil
elif Contains(c.toBind, s.id): nil
if s.owner == c.owner and s.kind == skParam: discard
elif contains(c.toBind, s.id): discard
elif templToExpand(s):
return semPatternBody(c, semTemplateExpr(c.c, n, s, false))
return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
if n.kind == nkInfix and n.sons[0].kind == nkIdent:
# we interpret `*` and `|` only as pattern operators if they occur in
@@ -537,15 +618,15 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# so we use the generic code for nkDotExpr too
case n.kind
of nkDotExpr, nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if Contains(c.toBind, s.id):
if contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
else:
return newIdentNode(s.name, n.info)
of nkPar:
if n.len == 1: return semPatternBody(c, n.sons[0])
else: nil
else: discard
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semPatternBody(c, n.sons[i])
@@ -554,6 +635,7 @@ proc semPattern(c: PContext, n: PNode): PNode =
var ctx: TemplCtx
ctx.toBind = initIntSet()
ctx.toMixin = initIntSet()
ctx.toInject = initIntSet()
ctx.c = c
ctx.owner = getCurrOwner()
result = flattenStmts(semPatternBody(ctx, n))
@@ -561,5 +643,5 @@ proc semPattern(c: PContext, n: PNode): PNode =
if result.len == 1:
result = result.sons[0]
elif result.len == 0:
LocalError(n.info, errInvalidExpression)
localError(n.info, errInvalidExpression)
closeScope(c)

View File

@@ -97,7 +97,7 @@ proc `==`(a, b: TCall): bool =
proc newProcCtx(owner: PSym): PProcCtx =
assert owner != nil
new(result)
result.mapping = tables.InitTable[int, TThreadOwner]()
result.mapping = tables.initTable[int, TThreadOwner]()
result.owner = owner
proc analyse(c: PProcCtx, n: PNode): TThreadOwner
@@ -119,7 +119,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
of skParam:
result = c.mapping[v.id]
if result == toUndefined:
InternalError(n.info, "param not set: " & v.name.s)
internalError(n.info, "param not set: " & v.name.s)
else:
result = toNil
c.mapping[v.id] = result
@@ -132,7 +132,7 @@ proc lvalueSym(n: PNode): PNode =
proc writeAccess(c: PProcCtx, n: PNode, owner: TThreadOwner) =
if owner notin {toNil, toMine, toTheirs}:
InternalError(n.info, "writeAccess: " & $owner)
internalError(n.info, "writeAccess: " & $owner)
var a = lvalueSym(n)
if a.kind == nkSym:
var v = a.sym
@@ -151,21 +151,21 @@ proc writeAccess(c: PProcCtx, n: PNode, owner: TThreadOwner) =
newOwner = toMine
# XXX BUG what if the tuple contains both ``tyRef`` and ``tyString``?
c.mapping[v.id] = newOwner
of toVoid, toUndefined: InternalError(n.info, "writeAccess")
of toTheirs: Message(n.info, warnWriteToForeignHeap)
of toVoid, toUndefined: internalError(n.info, "writeAccess")
of toTheirs: message(n.info, warnWriteToForeignHeap)
of toMine:
if lastOwner != owner and owner != toNil:
Message(n.info, warnDifferentHeaps)
message(n.info, warnDifferentHeaps)
else:
# we could not backtrack to a concrete symbol, but that's fine:
var lastOwner = analyse(c, n)
case lastOwner
of toNil: nil # fine, toNil can be overwritten
of toVoid, toUndefined: InternalError(n.info, "writeAccess")
of toTheirs: Message(n.info, warnWriteToForeignHeap)
of toNil: discard # fine, toNil can be overwritten
of toVoid, toUndefined: internalError(n.info, "writeAccess")
of toTheirs: message(n.info, warnWriteToForeignHeap)
of toMine:
if lastOwner != owner and owner != toNil:
Message(n.info, warnDifferentHeaps)
message(n.info, warnDifferentHeaps)
proc analyseAssign(c: PProcCtx, le, ri: PNode) =
var y = analyse(c, ri) # read access; ok
@@ -192,7 +192,7 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner =
result = analyse(newCtx, prc.getBody)
if prc.ast.sons[bodyPos].kind == nkEmpty and
{sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}:
Message(n.info, warnAnalysisLoophole, renderTree(n))
message(n.info, warnAnalysisLoophole, renderTree(n))
if result == toUndefined: result = toNil
if prc.typ.sons[0] != nil:
if prc.ast.len > resultPos:
@@ -215,12 +215,12 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner =
else: result = toNil
proc analyseVarTuple(c: PProcCtx, n: PNode) =
if n.kind != nkVarTuple: InternalError(n.info, "analyseVarTuple")
if n.kind != nkVarTuple: internalError(n.info, "analyseVarTuple")
var L = n.len
for i in countup(0, L-3): AnalyseAssign(c, n.sons[i], n.sons[L-1])
for i in countup(0, L-3): analyseAssign(c, n.sons[i], n.sons[L-1])
proc analyseSingleVar(c: PProcCtx, a: PNode) =
if a.sons[2].kind != nkEmpty: AnalyseAssign(c, a.sons[0], a.sons[2])
if a.sons[2].kind != nkEmpty: analyseAssign(c, a.sons[0], a.sons[2])
proc analyseVarSection(c: PProcCtx, n: PNode): TThreadOwner =
for i in countup(0, sonsLen(n) - 1):
@@ -238,7 +238,7 @@ proc analyseConstSection(c: PProcCtx, t: PNode): TThreadOwner =
for i in countup(0, sonsLen(t) - 1):
var it = t.sons[i]
if it.kind == nkCommentStmt: continue
if it.kind != nkConstDef: InternalError(t.info, "analyseConstSection")
if it.kind != nkConstDef: internalError(t.info, "analyseConstSection")
if sfFakeConst in it.sons[0].sym.flags: analyseSingleVar(c, it)
result = toVoid
@@ -246,7 +246,7 @@ template aggregateOwner(result, ana: expr) =
var a = ana # eval once
if result != a:
if result == toNil: result = a
elif a != toNil: Message(n.info, warnDifferentHeaps)
elif a != toNil: message(n.info, warnDifferentHeaps)
proc analyseArgs(c: PProcCtx, n: PNode, start = 1) =
for i in start..n.len-1: discard analyse(c, n[i])
@@ -254,7 +254,7 @@ proc analyseArgs(c: PProcCtx, n: PNode, start = 1) =
proc analyseOp(c: PProcCtx, n: PNode): TThreadOwner =
if n[0].kind != nkSym or n[0].sym.kind != skProc:
if {tfNoSideEffect, tfThread} * n[0].typ.flags == {}:
Message(n.info, warnAnalysisLoophole, renderTree(n))
message(n.info, warnAnalysisLoophole, renderTree(n))
result = toNil
else:
var prc = n[0].sym
@@ -352,13 +352,13 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
result = analyse(c, n.sons[0])
of nkRaiseStmt:
var a = analyse(c, n.sons[0])
if a != toMine: Message(n.info, warnDifferentHeaps)
if a != toMine: message(n.info, warnDifferentHeaps)
result = toVoid
of nkVarSection, nkLetSection: result = analyseVarSection(c, n)
of nkConstSection: result = analyseConstSection(c, n)
of nkTypeSection, nkCommentStmt: result = toVoid
of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt,
nkElifBranch, nkElse, nkExceptBranch, nkOfBranch:
nkElifBranch, nkElse, nkExceptBranch, nkOfBranch, nkFinally:
for i in 0 .. <n.len: discard analyse(c, n[i])
result = toVoid
of nkBreakStmt, nkContinueStmt: result = toVoid
@@ -369,11 +369,11 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
result = toMine
of nkAsmStmt, nkPragma, nkIteratorDef, nkProcDef, nkMethodDef,
nkConverterDef, nkMacroDef, nkTemplateDef,
nkGotoState, nkState, nkBreakState, nkType:
nkGotoState, nkState, nkBreakState, nkType, nkIdent:
result = toVoid
of nkExprColonExpr:
result = analyse(c, n.sons[1])
else: InternalError(n.info, "analysis not implemented for: " & $n.kind)
else: internalError(n.info, "analysis not implemented for: " & $n.kind)
proc analyseThreadProc*(prc: PSym) =
var c = newProcCtx(prc)

File diff suppressed because it is too large Load Diff

View File

@@ -11,21 +11,25 @@
import ast, astalgo, msgs, types, magicsys, semdata, renderer
const
tfInstClearedFlags = {tfHasMeta}
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
LocalError(info, errInvalidPragmaX, "acyclic")
localError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar:
LocalError(info, errVarVarTypeNotAllowed)
localError(info, errVarVarTypeNotAllowed)
proc checkConstructedType*(info: TLineInfo, typ: PType) =
proc checkConstructedType*(info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct})
if t.kind in {tyTypeClass}: nil
if t.kind in tyTypeClasses: discard
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
LocalError(info, errInvalidPragmaX, "acyclic")
localError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar:
LocalError(info, errVarVarTypeNotAllowed)
elif computeSize(t) < 0:
LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t))
when false:
if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@@ -33,7 +37,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
proc searchInstTypes*(key: PType): PType =
let genericTyp = key.sons[0]
InternalAssert genericTyp.kind == tyGenericBody and
internalAssert genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and
genericTyp.sym != nil
@@ -47,12 +51,13 @@ proc searchInstTypes*(key: PType): PType =
# types such as TChannel[empty]. Why?
# See the notes for PActor in handleGenericInvokation
return
block MatchType:
block matchType:
for j in 1 .. high(key.sons):
# XXX sameType is not really correct for nested generics?
if not sameType(inst.sons[j], key.sons[j]):
break MatchType
if not compareTypes(inst.sons[j], key.sons[j],
flags = {ExactGenericParams}):
break matchType
return inst
proc cacheTypeInst*(inst: PType) =
@@ -66,30 +71,95 @@ type
c*: PContext
typeMap*: TIdTable # map PType to PType
symMap*: TIdTable # map PSym to PSym
localCache*: TIdTable # local cache for remembering alraedy replaced
# types during instantiation of meta types
# (they are not stored in the global cache)
info*: TLineInfo
allowMetaTypes*: bool # allow types such as seq[Number]
# i.e. the result contains unresolved generics
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode): PNode
template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
when false:
if t != nil and tfHasMeta in t.flags and
cl.allowMetaTypes == false:
echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
debug t
writeStackTrace()
quit 1
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = replaceTypeVarsTAux(cl, t)
checkMetaInvariants(cl, result)
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
let t = replaceTypeVarsT(cl, n.typ)
if t != nil and t.kind == tyStatic and t.n != nil:
return t.n
result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ)
if result.kind == nkSym: result.sym = ReplaceTypeVarsS(cl, n.sym)
for i in 0 .. safeLen(n)-1:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if i == 0: result.add(n[i])
result.typ = t
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
let isCall = result.kind in nkCallKinds
for i in 0 .. <n.safeLen:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if isCall and i == 0: result.add(n[i])
else: result.add(prepareNode(cl, n[i]))
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
proc isTypeParam(n: PNode): bool =
# XXX: generic params should use skGenericParam instead of skType
return n.kind == nkSym and
(n.sym.kind == skGenericParam or
(n.sym.kind == skType and sfFromGeneric in n.sym.flags))
proc hasGenericArguments*(n: PNode): bool =
if n.kind == nkSym:
return n.sym.kind == skGenericParam or
(n.sym.kind == skType and
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
else:
for i in 0.. <n.safeLen:
if hasGenericArguments(n.sons[i]): return true
return false
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
# This is needed fo tgenericshardcases
# It's possible that a generic param will be used in a proc call to a
# typedesc accepting proc. After generic param substitution, such procs
# should be optionally instantiated with the correct type. In order to
# perform this instantiation, we need to re-run the generateInstance path
# in the compiler, but it's quite complicated to do so at the moment so we
# resort to a mild hack; the head symbol of the call is temporary reset and
# overload resolution is executed again (which may trigger generateInstance).
if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags:
var needsFixing = false
for i in 1 .. <n.safeLen:
if isTypeParam(n[i]): needsFixing = true
if needsFixing:
n.sons[0] = newSymNode(n.sons[0].sym.owner)
return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
for i in 0 .. <n.safeLen:
n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
return n
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n == nil: return
result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ)
if n.typ != nil:
result.typ = replaceTypeVarsT(cl, n.typ)
checkMetaInvariants(cl, result.typ)
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
nil
discard
of nkSym:
result.sym = ReplaceTypeVarsS(cl, n.sym)
result.sym = replaceTypeVarsS(cl, n.sym)
if result.sym.typ.kind == tyEmpty:
# don't add the 'void' field
result = newNode(nkRecList, n.info)
of nkRecWhen:
var branch: PNode = nil # the branch to take
for i in countup(0, sonsLen(n) - 1):
@@ -101,72 +171,95 @@ proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
var cond = prepareNode(cl, it.sons[0])
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
InternalError(e.info, "ReplaceTypeVarsN: when condition not a bool")
internalError(e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it.sons[1]
of nkElse:
checkSonsLen(it, 1)
if branch == nil: branch = it.sons[0]
else: illFormedAst(n)
if branch != nil:
result = ReplaceTypeVarsN(cl, branch)
result = replaceTypeVarsN(cl, branch)
else:
result = newNodeI(nkRecList, n.info)
of nkStaticExpr:
var n = prepareNode(cl, n)
n = reResolveCallsWithTypedescParams(cl, n)
result = if cl.allowMetaTypes: n
else: cl.c.semExpr(cl.c, n)
else:
var length = sonsLen(n)
if length > 0:
newSons(result, length)
for i in countup(0, length - 1):
result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: return nil
result = PSym(idTableGet(cl.symMap, s))
if result == nil:
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result)
result.typ = ReplaceTypeVarsT(cl, s.typ)
result.owner = s.owner
result.ast = ReplaceTypeVarsN(cl, s.ast)
result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
LocalError(t.sym.info, errCannotInstantiateX, typeToString(t))
if cl.allowMetaTypes or tfRetType in t.flags: return
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
result = errorType(cl.c)
elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter")
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter")
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
# XXX: relying on allowMetaTypes is a kludge
result = copyType(t, t.owner, cl.allowMetaTypes)
result.flags.incl tfFromGeneric
result.flags.excl tfInstClearedFlags
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
# is difficult to handle:
var body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
var header: PType = nil
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
var header: PType = t
# search for some instantiation here:
result = searchInstTypes(t)
if cl.allowMetaTypes:
result = PType(idTableGet(cl.localCache, t))
else:
result = searchInstTypes(t)
if result != nil: return
for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i]
if x.kind == tyGenericParam:
x = lookupTypeVar(cl, x)
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
if x != nil:
if header == t: header = instCopyType(cl, t)
header.sons[i] = x
propagateToOwner(header, x)
else:
propagateToOwner(header, x)
#idTablePut(cl.typeMap, body.sons[i-1], x)
if header != nil:
if header != t:
# search again after first pass:
result = searchInstTypes(header)
if result != nil: return
else:
header = copyType(t, t.owner, false)
header = instCopyType(cl, t)
result = newType(tyGenericInst, t.sons[0].owner)
result.flags = header.flags
# be careful not to propagate unnecessary flags here (don't use rawAddSon)
result.sons = @[header.sons[0]]
# ugh need another pass for deeply recursive generic types (e.g. PActor)
# we need to add the candidate here, before it's fully instantiated for
# recursive instantions:
result = newType(tyGenericInst, t.sons[0].owner)
result.rawAddSon(header.sons[0])
cacheTypeInst(result)
if not cl.allowMetaTypes:
cacheTypeInst(result)
else:
idTablePut(cl.localCache, t, result)
for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i])
@@ -175,71 +268,171 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
propagateToOwner(header, x)
idTablePut(cl.typeMap, body.sons[i-1], x)
for i in countup(1, sonsLen(t) - 1):
for i in countup(1, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
rawAddSon(result, header.sons[i])
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
var newbody = replaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags
newbody.callConv = body.callConv
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
# This type may be a generic alias and we want to resolve it here.
# One step is enough, because the recursive nature of
# handleGenericInvokation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
proc eraseVoidParams*(t: PType) =
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
t.sons[0] = nil
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
for i in 1 .. <t.sonsLen:
# don't touch any memory unless necessary
if t.sons[i].kind == tyEmpty:
var pos = i
for j in i+1 .. <t.sonsLen:
if t.sons[j].kind != tyEmpty:
t.sons[pos] = t.sons[j]
t.n.sons[pos] = t.n.sons[j]
inc pos
setLen t.sons, pos
setLen t.n.sons, pos
return
proc skipIntLiteralParams*(t: PType) =
for i in 0 .. <t.sonsLen:
let p = t.sons[i]
if p == nil: continue
let skipped = p.skipIntLit
if skipped != p:
t.sons[i] = skipped
if i > 0: t.n.sons[i].sym.typ = skipped
# when the typeof operator is used on a static input
# param, the results gets infected with static as well:
if t.sons[0] != nil and t.sons[0].kind == tyStatic:
t.sons[0] = t.sons[0].base
proc propagateFieldFlags(t: PType, n: PNode) =
# This is meant for objects and tuples
# The type must be fully instantiated!
internalAssert n.kind != nkRecWhen
case n.kind
of nkSym:
propagateToOwner(t, n.sym.typ)
of nkRecList, nkRecCase, nkOfBranch, nkElse:
for son in n:
propagateFieldFlags(t, son)
else: discard
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = t
if t == nil: return
if t == nil: return
if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
let lookup = PType(idTableGet(cl.typeMap, t))
if lookup != nil: return lookup
case t.kind
of tyTypeClass: nil
of tyGenericParam:
result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation:
result = handleGenericInvokation(cl, result)
of tyExpr:
if t.sym != nil and t.sym.kind == skGenericParam:
result = lookupTypeVar(cl, t)
of tyGenericInvokation:
of tyGenericInvokation:
result = handleGenericInvokation(cl, t)
of tyGenericBody:
InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
result = ReplaceTypeVarsT(cl, lastSon(t))
internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody" )
result = replaceTypeVarsT(cl, lastSon(t))
of tyFromExpr:
if cl.allowMetaTypes: return
var n = prepareNode(cl, t.n)
n = cl.c.semConstExpr(cl.c, n)
if n.typ.kind == tyTypeDesc:
# XXX: sometimes, chained typedescs enter here.
# It may be worth investigating why this is happening,
# because it may cause other bugs elsewhere.
result = n.typ.skipTypes({tyTypeDesc})
# result = n.typ.base
else:
if n.typ.kind != tyStatic:
# XXX: In the future, semConstExpr should
# return tyStatic values to let anyone make
# use of this knowledge. The patching here
# won't be necessary then.
result = newTypeS(tyStatic, cl.c)
result.sons = @[n.typ]
result.n = n
else:
result = n.typ
of tyInt:
result = skipIntLit(t)
# XXX now there are also float literals
else:
if t.kind == tyArray:
let idxt = t.sons[0]
if idxt.kind == tyExpr and
idxt.sym != nil and idxt.sym.kind == skGenericParam:
let value = lookupTypeVar(cl, idxt).n
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
if containsGenericType(t):
result = copyType(t, t.owner, false)
incl(result.flags, tfFromGeneric)
result.size = -1 # needs to be recomputed
for i in countup(0, sonsLen(result) - 1):
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
if result.kind == tyProc and result.sons[0] != nil:
if result.sons[0].kind == tyEmpty:
result.sons[0] = nil
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt)
cl.info = arg.info
cl.c = p
pushInfoContext(arg.info)
result = ReplaceTypeVarsT(cl, t)
of tyTypeDesc:
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
if lookup != nil:
result = lookup
if tfUnresolved in t.flags: result = result.base
elif t.sons[0].kind != tyNone:
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
of tyUserTypeClass:
result = t
of tyGenericInst:
result = instCopyType(cl, t)
for i in 1 .. <result.sonsLen:
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.lastSon)
else:
if containsGenericType(t):
result = instCopyType(cl, t)
result.size = -1 # needs to be recomputed
for i in countup(0, sonsLen(result) - 1):
if result.sons[i] != nil:
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
result.n = replaceTypeVarsN(cl, result.n)
case result.kind
of tyArray:
let idx = result.sons[0]
internalAssert idx.kind != tyStatic
of tyObject, tyTuple:
propagateFieldFlags(result, result.n)
of tyProc:
eraseVoidParams(result)
skipIntLiteralParams(result)
else: discard
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
initIdTable(result.symMap)
copyIdTable(result.typeMap, pt)
initIdTable(result.localCache)
result.info = info
result.c = p
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
var cl = initTypeVars(p, pt, n.info)
pushInfoContext(n.info)
result = replaceTypeVarsN(cl, n)
popInfoContext()
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType =
var cl = initTypeVars(p, pt, info)
pushInfoContext(info)
result = replaceTypeVarsT(cl, t)
popInfoContext()
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): expr =
generateTypeInstance(p, pt, arg.info, t)

View File

@@ -29,23 +29,23 @@ var
# the arguments to be passed to the program that
# should be run
proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongOption, cmdShortOption:
of cmdLongoption, cmdShortOption:
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here
var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val
ProcessSwitch(key, val, pass, gCmdLineInfo)
processSwitch(key, val, pass, gCmdLineInfo)
else:
ProcessSwitch(p.key, p.val, pass, gCmdLineInfo)
processSwitch(p.key, p.val, pass, gCmdLineInfo)
of cmdArgument:
if argsCount == 0:
options.command = p.key
@@ -79,11 +79,11 @@ proc serve*(action: proc (){.nimcall.}) =
if line == "quit": quit()
execute line
echo ""
FlushFile(stdout)
flushFile(stdout)
of "tcp", "":
when useCaas:
var server = Socket()
var server = socket()
let p = getConfigVar("server.port")
let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
server.bindAddr(port, getConfigVar("server.address"))

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
# included from sigmatch.nim
import algorithm, sequtils
import algorithm, sequtils, pretty
const
sep = '\t'
@@ -28,7 +28,7 @@ proc origModuleName(m: PSym): string =
else:
m.name.s
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
result = section
result.add(sep)
result.add($s.kind)
@@ -48,15 +48,15 @@ proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
result.add(sep)
result.add(toFullPath(li))
result.add(sep)
result.add($ToLinenumber(li))
result.add($toLinenumber(li))
result.add(sep)
result.add($ToColumn(li))
result.add($toColumn(li))
result.add(sep)
when not defined(noDocgen):
result.add(s.extractDocComment.escape)
proc SymToStr(s: PSym, isLocal: bool, section: string): string =
result = SymToStr(s, isLocal, section, s.info)
proc symToStr(s: PSym, isLocal: bool, section: string): string =
result = symToStr(s, isLocal, section, s.info)
proc filterSym(s: PSym): bool {.inline.} =
result = s.name.s[0] in lexer.SymChars and s.kind != skModule
@@ -68,7 +68,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
proc suggestField(c: PContext, s: PSym, outputs: var int) =
if filterSym(s) and fieldVisible(c, s):
SuggestWriteln(SymToStr(s, isLocal=true, sectionSuggest))
suggestWriteln(symToStr(s, isLocal=true, sectionSuggest))
inc outputs
when not defined(nimhygiene):
@@ -84,7 +84,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
for item in entries:
let it {.inject.} = item
if cond:
SuggestWriteln(SymToStr(it, isLocal = isLocal, section))
suggestWriteln(symToStr(it, isLocal = isLocal, section))
inc outputs
proc suggestSymList(c: PContext, list: PNode, outputs: var int) =
@@ -103,7 +103,7 @@ proc suggestObject(c: PContext, n: PNode, outputs: var int) =
suggestObject(c, n.sons[0], outputs)
for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), outputs)
of nkSym: suggestField(c, n.sym, outputs)
else: nil
else: discard
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
var op = n.sons[0]
@@ -119,7 +119,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
case candidate.kind
of OverloadableSyms:
var m: TCandidate
initCandidate(m, candidate, nil)
initCandidate(c, m, candidate, nil)
sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch
else:
@@ -144,14 +144,14 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
if scope == c.topLevelScope: isLocal = false
for it in items(scope.symbols):
if filterSym(it):
SuggestWriteln(SymToStr(it, isLocal = isLocal, sectionSuggest))
suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest))
inc outputs
if scope == c.topLevelScope: break
proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
# ``myObj``.
var typ = n.Typ
var typ = n.typ
if typ == nil:
# a module symbol has no type for example:
if n.kind == nkSym and n.sym.kind == skModule:
@@ -159,12 +159,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
# all symbols accessible, because we are in the current module:
for it in items(c.topLevelScope.symbols):
if filterSym(it):
SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
inc outputs
else:
for it in items(n.sym.tab):
if filterSym(it):
SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
inc outputs
else:
# fallback:
@@ -203,7 +203,7 @@ const
CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit}
proc findClosestCall(n: PNode): PNode =
if n.kind in callNodes and msgs.inCheckpoint(n.info) == cpExact:
if n.kind in CallNodes and msgs.inCheckpoint(n.info) == cpExact:
result = n
else:
for i in 0.. <safeLen(n):
@@ -246,16 +246,16 @@ var
proc findUsages(node: PNode, s: PSym) =
if usageSym == nil and isTracked(node.info, s.name.s.len):
usageSym = s
SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage))
suggestWriteln(symToStr(s, isLocal=false, sectionUsage))
elif s == usageSym:
if lastLineInfo != node.info:
SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info))
suggestWriteln(symToStr(s, isLocal=false, sectionUsage, node.info))
lastLineInfo = node.info
proc findDefinition(node: PNode, s: PSym) =
if isTracked(node.info, s.name.s.len):
SuggestWriteln(SymToStr(s, isLocal=false, sectionDef))
SuggestQuit()
suggestWriteln(symToStr(s, isLocal=false, sectionDef))
suggestQuit()
type
TSourceMap = object
@@ -281,7 +281,7 @@ proc resetSourceMap*(fileIdx: int32) =
ensureIdx(gSourceMaps, fileIdx)
gSourceMaps[fileIdx].lines = @[]
proc addToSourceMap(sym: Psym, info: TLineInfo) =
proc addToSourceMap(sym: PSym, info: TLineInfo) =
ensureIdx(gSourceMaps, info.fileIndex)
ensureSeq(gSourceMaps[info.fileIndex].lines)
ensureIdx(gSourceMaps[info.fileIndex].lines, info.line)
@@ -302,7 +302,7 @@ proc defFromLine(entries: var seq[TEntry], col: int32) =
# that the first expr that ends after the cursor column is
# the one we are looking for.
if e.pos >= col:
SuggestWriteln(SymToStr(e.sym, isLocal=false, sectionDef))
suggestWriteln(symToStr(e.sym, isLocal=false, sectionDef))
return
proc defFromSourceMap*(i: TLineInfo) =
@@ -324,9 +324,10 @@ proc suggestSym*(n: PNode, s: PSym) {.inline.} =
proc markUsed(n: PNode, s: PSym) =
incl(s.flags, sfUsed)
if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
if sfDeprecated in s.flags: message(n.info, warnDeprecated, s.name.s)
if sfError in s.flags: localError(n.info, errWrongSymbolX, s.name.s)
suggestSym(n, s)
if gCmd == cmdPretty: checkUse(n, s)
proc useSym*(sym: PSym): PNode =
result = newSymNode(sym)
@@ -337,8 +338,8 @@ proc suggestExpr*(c: PContext, node: PNode) =
if cp == cpNone: return
var outputs = 0
# This keeps semExpr() from coming here recursively:
if c.InCompilesContext > 0: return
inc(c.InCompilesContext)
if c.inCompilesContext > 0: return
inc(c.inCompilesContext)
if optSuggest in gGlobalOptions:
var n = findClosestDot(node)
@@ -368,8 +369,8 @@ proc suggestExpr*(c: PContext, node: PNode) =
addSon(a, x)
suggestCall(c, a, n, outputs)
dec(c.InCompilesContext)
if outputs > 0 and optUsages notin gGlobalOptions: SuggestQuit()
dec(c.inCompilesContext)
if outputs > 0 and optUsages notin gGlobalOptions: suggestQuit()
proc suggestStmt*(c: PContext, n: PNode) =
suggestExpr(c, n)

View File

@@ -17,14 +17,15 @@ type
TFilterKind* = enum
filtNone, filtTemplate, filtReplace, filtStrip
TParserKind* = enum
skinStandard, skinBraces, skinEndX
skinStandard, skinStrongSpaces, skinBraces, skinEndX
const
parserNames*: array[TParserKind, string] = ["standard", "braces", "endx"]
filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
"strip"]
parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
"braces", "endx"]
filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
"strip"]
type
type
TParsers*{.final.} = object
skin*: TParserKind
parser*: TParser
@@ -40,41 +41,41 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
# implementation
proc ParseFile(fileIdx: int32): PNode =
proc parseFile(fileIdx: int32): PNode =
var
p: TParsers
f: tfile
f: TFile
let filename = fileIdx.toFullPath
if not open(f, filename):
rawMessage(errCannotOpenFile, filename)
return
OpenParsers(p, fileIdx, LLStreamOpen(f))
result = ParseAll(p)
CloseParsers(p)
openParsers(p, fileIdx, llStreamOpen(f))
result = parseAll(p)
closeParsers(p)
proc parseAll(p: var TParsers): PNode =
case p.skin
of skinStandard:
of skinStandard, skinStrongSpaces:
result = parser.parseAll(p.parser)
of skinBraces:
result = pbraces.parseAll(p.parser)
of skinEndX:
InternalError("parser to implement")
internalError("parser to implement")
result = ast.emptyNode
# skinEndX: result := pendx.parseAll(p.parser);
proc parseTopLevelStmt(p: var TParsers): PNode =
case p.skin
of skinStandard:
of skinStandard, skinStrongSpaces:
result = parser.parseTopLevelStmt(p.parser)
of skinBraces:
result = pbraces.parseTopLevelStmt(p.parser)
of skinEndX:
InternalError("parser to implement")
internalError("parser to implement")
result = ast.emptyNode
#skinEndX: result := pendx.parseTopLevelStmt(p.parser);
proc UTF8_BOM(s: string): int =
proc utf8Bom(s: string): int =
if (s[0] == '\xEF') and (s[1] == '\xBB') and (s[2] == '\xBF'):
result = 3
else:
@@ -83,37 +84,37 @@ proc UTF8_BOM(s: string): int =
proc containsShebang(s: string, i: int): bool =
if (s[i] == '#') and (s[i + 1] == '!'):
var j = i + 2
while s[j] in WhiteSpace: inc(j)
while s[j] in Whitespace: inc(j)
result = s[j] == '/'
proc parsePipe(filename: string, inputStream: PLLStream): PNode =
result = ast.emptyNode
var s = LLStreamOpen(filename, fmRead)
var s = llStreamOpen(filename, fmRead)
if s != nil:
var line = newStringOfCap(80)
discard LLStreamReadLine(s, line)
var i = UTF8_Bom(line)
discard llStreamReadLine(s, line)
var i = utf8Bom(line)
if containsShebang(line, i):
discard LLStreamReadLine(s, line)
discard llStreamReadLine(s, line)
i = 0
if line[i] == '#' and line[i+1] == '!':
inc(i, 2)
while line[i] in WhiteSpace: inc(i)
while line[i] in Whitespace: inc(i)
var q: TParser
OpenParser(q, filename, LLStreamOpen(substr(line, i)))
openParser(q, filename, llStreamOpen(substr(line, i)))
result = parser.parseAll(q)
CloseParser(q)
LLStreamClose(s)
closeParser(q)
llStreamClose(s)
proc getFilter(ident: PIdent): TFilterKind =
for i in countup(low(TFilterKind), high(TFilterKind)):
if IdentEq(ident, filterNames[i]):
if identEq(ident, filterNames[i]):
return i
result = filtNone
proc getParser(ident: PIdent): TParserKind =
for i in countup(low(TParserKind), high(TParserKind)):
if IdentEq(ident, parserNames[i]):
if identEq(ident, parserNames[i]):
return i
rawMessage(errInvalidDirectiveX, ident.s)
@@ -142,35 +143,37 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string,
if f != filtNone:
if gVerbosity >= 2:
rawMessage(hintCodeBegin, [])
MsgWriteln(result.s)
msgWriteln(result.s)
rawMessage(hintCodeEnd, [])
proc evalPipe(p: var TParsers, n: PNode, filename: string,
start: PLLStream): PLLStream =
result = start
if n.kind == nkEmpty: return
if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and
IdentEq(n.sons[0].ident, "|"):
for i in countup(1, 2):
if n.sons[i].kind == nkInfix:
if n.kind == nkInfix and n.sons[0].kind == nkIdent and
identEq(n.sons[0].ident, "|"):
for i in countup(1, 2):
if n.sons[i].kind == nkInfix:
result = evalPipe(p, n.sons[i], filename, result)
else:
else:
result = applyFilter(p, n.sons[i], filename, result)
elif n.kind == nkStmtList:
elif n.kind == nkStmtList:
result = evalPipe(p, n.sons[0], filename, result)
else:
else:
result = applyFilter(p, n, filename, result)
proc openParsers(p: var TParsers, fileIdx: int32, inputstream: PLLStream) =
var s: PLLStream
p.skin = skinStandard
let filename = fileIdx.toFullPath
var pipe = parsePipe(filename, inputStream)
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
else: s = inputStream
var pipe = parsePipe(filename, inputstream)
if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
else: s = inputstream
case p.skin
of skinStandard, skinBraces, skinEndX:
parser.openParser(p.parser, fileIdx, s)
parser.openParser(p.parser, fileIdx, s, false)
of skinStrongSpaces:
parser.openParser(p.parser, fileIdx, s, true)
proc closeParsers(p: var TParsers) =
proc closeParsers(p: var TParsers) =
parser.closeParser(p.parser)

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