mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-06 13:07:48 +00:00
resolved conflict
This commit is contained in:
1
bin/empty.txt
Normal file
1
bin/empty.txt
Normal file
@@ -0,0 +1 @@
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
1
build/empty.txt
Normal file
1
build/empty.txt
Normal file
@@ -0,0 +1 @@
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
@@ -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
|
||||
|
||||
|
||||
242
compiler/ast.nim
242
compiler/ast.nim
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
33
compiler/c2nim/tests/vincent.c
Normal file
33
compiler/c2nim/tests/vincent.c
Normal 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';
|
||||
}
|
||||
3
compiler/c2nim/tests/vincent.h
Normal file
3
compiler/c2nim/tests/vincent.h
Normal file
@@ -0,0 +1,3 @@
|
||||
struct foo {
|
||||
int x,y,z;
|
||||
};
|
||||
416
compiler/canonicalizer.nim
Normal file
416
compiler/canonicalizer.nim
Normal 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);
|
||||
# """, [])
|
||||
|
||||
@@ -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, ~" ")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 & ')')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
52
compiler/lowerings.nim
Normal 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))
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
221
compiler/sem.nim
221
compiler/sem.nim
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
89
compiler/semmacrosanity.nim
Normal file
89
compiler/semmacrosanity.nim
Normal 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
|
||||
@@ -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})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user