Merge branch 'devel'
This commit is contained in:
commit
98751caed4
231 changed files with 15082 additions and 10779 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -263,7 +263,7 @@ type
|
||||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||||
# language; for interfacing with Objective C
|
# language; for interfacing with Objective C
|
||||||
sfDiscardable, # returned value may be discarded implicitly
|
sfDiscardable, # returned value may be discarded implicitly
|
||||||
sfDestructor, # proc is destructor
|
sfOverriden, # proc is overriden
|
||||||
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
||||||
|
|
||||||
TSymFlags* = set[TSymFlag]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
@ -291,6 +291,8 @@ const
|
||||||
|
|
||||||
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
||||||
# require RC ops
|
# require RC ops
|
||||||
|
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||||
|
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
|
|
@ -417,6 +419,7 @@ type
|
||||||
# efficiency
|
# efficiency
|
||||||
nfTransf, # node has been transformed
|
nfTransf, # node has been transformed
|
||||||
nfSem # node has been checked for semantics
|
nfSem # node has been checked for semantics
|
||||||
|
nfLL # node has gone through lambda lifting
|
||||||
nfDotField # the call can use a dot operator
|
nfDotField # the call can use a dot operator
|
||||||
nfDotSetter # the call can use a setter dot operarator
|
nfDotSetter # the call can use a setter dot operarator
|
||||||
nfExplicitCall # x.y() was used instead of x.y
|
nfExplicitCall # x.y() was used instead of x.y
|
||||||
|
|
@ -475,7 +478,7 @@ type
|
||||||
# and first phase symbol lookup in generics
|
# and first phase symbol lookup in generics
|
||||||
skConditional, # symbol for the preprocessor (may become obsolete)
|
skConditional, # symbol for the preprocessor (may become obsolete)
|
||||||
skDynLib, # symbol represents a dynamic library; this is used
|
skDynLib, # symbol represents a dynamic library; this is used
|
||||||
# internally; it does not exist in Nimrod code
|
# internally; it does not exist in Nim code
|
||||||
skParam, # a parameter
|
skParam, # a parameter
|
||||||
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
|
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
|
||||||
skTemp, # a temporary variable (introduced by compiler)
|
skTemp, # a temporary variable (introduced by compiler)
|
||||||
|
|
@ -500,7 +503,8 @@ type
|
||||||
skStub, # symbol is a stub and not yet loaded from the ROD
|
skStub, # symbol is a stub and not yet loaded from the ROD
|
||||||
# file (it is loaded on demand, which may
|
# file (it is loaded on demand, which may
|
||||||
# mean: never)
|
# mean: never)
|
||||||
skPackage # symbol is a package (used for canonicalization)
|
skPackage, # symbol is a package (used for canonicalization)
|
||||||
|
skAlias # an alias (needs to be resolved immediately)
|
||||||
TSymKinds* = set[TSymKind]
|
TSymKinds* = set[TSymKind]
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -552,7 +556,7 @@ type
|
||||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||||
mIsPartOf, mAstToStr, mParallel,
|
mIsPartOf, mAstToStr, mParallel,
|
||||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||||
mNewString, mNewStringOfCap,
|
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||||
mReset,
|
mReset,
|
||||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||||
mOrdinal,
|
mOrdinal,
|
||||||
|
|
@ -677,7 +681,7 @@ type
|
||||||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||||
# owns this location (required by GC algorithms
|
# owns this location (required by GC algorithms
|
||||||
# employing heap snapshots or sliding views)
|
# employing heap snapshots or sliding views)
|
||||||
a*: int # location's "address", i.e. slot for temporaries
|
a*: int
|
||||||
|
|
||||||
# ---------------- end of backend information ------------------------------
|
# ---------------- end of backend information ------------------------------
|
||||||
|
|
||||||
|
|
@ -730,8 +734,9 @@ type
|
||||||
# check for the owner when touching 'usedGenerics'.
|
# check for the owner when touching 'usedGenerics'.
|
||||||
usedGenerics*: seq[PInstantiation]
|
usedGenerics*: seq[PInstantiation]
|
||||||
tab*: TStrTable # interface table for modules
|
tab*: TStrTable # interface table for modules
|
||||||
|
of skLet, skVar, skField:
|
||||||
|
guard*: PSym
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
magic*: TMagic
|
magic*: TMagic
|
||||||
typ*: PType
|
typ*: PType
|
||||||
name*: PIdent
|
name*: PIdent
|
||||||
|
|
@ -784,12 +789,13 @@ type
|
||||||
# the body of the user-defined type class
|
# the body of the user-defined type class
|
||||||
# formal param list
|
# formal param list
|
||||||
# else: unused
|
# else: unused
|
||||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
|
||||||
# mean that there is no destructor.
|
|
||||||
# see instantiateDestructor in types.nim
|
|
||||||
owner*: PSym # the 'owner' of the type
|
owner*: PSym # the 'owner' of the type
|
||||||
sym*: PSym # types have the sym associated with them
|
sym*: PSym # types have the sym associated with them
|
||||||
# it is used for converting types to strings
|
# it is used for converting types to strings
|
||||||
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
|
# mean that there is no destructor.
|
||||||
|
# see instantiateDestructor in semdestruct.nim
|
||||||
|
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||||
size*: BiggestInt # the size of the type in bytes
|
size*: BiggestInt # the size of the type in bytes
|
||||||
# -1 means that the size is unkwown
|
# -1 means that the size is unkwown
|
||||||
align*: int # the type's alignment requirements
|
align*: int # the type's alignment requirements
|
||||||
|
|
@ -870,7 +876,7 @@ const
|
||||||
tyProc, tyString, tyError}
|
tyProc, tyString, tyError}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
||||||
skIterator, skClosureIterator,
|
skIterator, skClosureIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||||
nfDotSetter, nfDotField,
|
nfDotSetter, nfDotField,
|
||||||
nfIsRef}
|
nfIsRef}
|
||||||
|
|
@ -1160,7 +1166,6 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||||
result.sons = @[name, pattern, genericParams, params,
|
result.sons = @[name, pattern, genericParams, params,
|
||||||
pragmas, exceptions, body]
|
pragmas, exceptions, body]
|
||||||
|
|
||||||
|
|
||||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = kind
|
result.kind = kind
|
||||||
|
|
@ -1170,8 +1175,8 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
result.id = getID()
|
result.id = getID()
|
||||||
when debugIds:
|
when debugIds:
|
||||||
registerId(result)
|
registerId(result)
|
||||||
#if result.id < 2000 then
|
#if result.id < 2000:
|
||||||
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||||
|
|
||||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||||
if a.k == low(a.k): a.k = b.k
|
if a.k == low(a.k): a.k = b.k
|
||||||
|
|
@ -1189,6 +1194,7 @@ proc assignType(dest, src: PType) =
|
||||||
dest.size = src.size
|
dest.size = src.size
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.destructor = src.destructor
|
dest.destructor = src.destructor
|
||||||
|
dest.deepCopy = src.deepCopy
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
@ -1226,6 +1232,8 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||||
result.position = s.position
|
result.position = s.position
|
||||||
result.loc = s.loc
|
result.loc = s.loc
|
||||||
result.annex = s.annex # BUGFIX
|
result.annex = s.annex # BUGFIX
|
||||||
|
if result.kind in {skVar, skLet, skField}:
|
||||||
|
result.guard = s.guard
|
||||||
|
|
||||||
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
||||||
result = newSym(s.kind, newIdent, s.owner, info)
|
result = newSym(s.kind, newIdent, s.owner, info)
|
||||||
|
|
@ -1310,6 +1318,10 @@ proc newSons(father: PNode, length: int) =
|
||||||
setLen(father.sons, length)
|
setLen(father.sons, length)
|
||||||
|
|
||||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||||
|
## Used throughout the compiler code to test whether a type tree contains or
|
||||||
|
## doesn't contain a specific type/types - it is often the case that only the
|
||||||
|
## last child nodes of a type tree need to be searched. This is a really hot
|
||||||
|
## path within the compiler!
|
||||||
result = t
|
result = t
|
||||||
while result.kind in kinds: result = lastSon(result)
|
while result.kind in kinds: result = lastSon(result)
|
||||||
|
|
||||||
|
|
@ -1505,7 +1517,7 @@ proc isGenericRoutine*(s: PSym): bool =
|
||||||
proc skipGenericOwner*(s: PSym): PSym =
|
proc skipGenericOwner*(s: PSym): PSym =
|
||||||
internalAssert s.kind in skProcKinds
|
internalAssert s.kind in skProcKinds
|
||||||
## Generic instantiations are owned by their originating generic
|
## Generic instantiations are owned by their originating generic
|
||||||
## symbol. This proc skips such owners and goes straigh to the owner
|
## symbol. This proc skips such owners and goes straight to the owner
|
||||||
## of the generic itself (the module or the enclosing proc).
|
## of the generic itself (the module or the enclosing proc).
|
||||||
result = if sfFromGeneric in s.flags: s.owner.owner
|
result = if sfFromGeneric in s.flags: s.owner.owner
|
||||||
else: s.owner
|
else: s.owner
|
||||||
|
|
|
||||||
|
|
@ -116,17 +116,16 @@ proc iiTablePut*(t: var TIITable, key, val: int)
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc skipConv*(n: PNode): PNode =
|
proc skipConvAndClosure*(n: PNode): PNode =
|
||||||
case n.kind
|
result = n
|
||||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
while true:
|
||||||
result = n.sons[0]
|
case result.kind
|
||||||
|
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
|
||||||
|
nkClosure:
|
||||||
|
result = result.sons[0]
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
result = n.sons[1]
|
result = result.sons[1]
|
||||||
else: result = n
|
else: break
|
||||||
|
|
||||||
proc skipConvTakeType*(n: PNode): PNode =
|
|
||||||
result = n.skipConv
|
|
||||||
result.typ = n.typ
|
|
||||||
|
|
||||||
proc sameValue*(a, b: PNode): bool =
|
proc sameValue*(a, b: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
|
|
@ -379,8 +378,8 @@ proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
result = symToYamlAux(n, marker, indent, maxRecDepth)
|
result = symToYamlAux(n, marker, indent, maxRecDepth)
|
||||||
|
|
||||||
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope
|
proc debugTree(n: PNode, indent: int, maxRecDepth: int; renderType=false): PRope
|
||||||
proc debugType(n: PType): PRope =
|
proc debugType(n: PType, maxRecDepth=100): PRope =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
|
|
@ -388,20 +387,21 @@ proc debugType(n: PType): PRope =
|
||||||
if n.sym != nil:
|
if n.sym != nil:
|
||||||
app(result, " ")
|
app(result, " ")
|
||||||
app(result, n.sym.name.s)
|
app(result, n.sym.name.s)
|
||||||
if (n.kind != tyString) and (sonsLen(n) > 0):
|
if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
|
||||||
app(result, "(")
|
app(result, "(")
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ", ")
|
if i > 0: app(result, ", ")
|
||||||
if n.sons[i] == nil:
|
if n.sons[i] == nil:
|
||||||
app(result, "null")
|
app(result, "null")
|
||||||
else:
|
else:
|
||||||
app(result, debugType(n.sons[i]))
|
app(result, debugType(n.sons[i], maxRecDepth-1))
|
||||||
if n.kind == tyObject and n.n != nil:
|
if n.kind == tyObject and n.n != nil:
|
||||||
app(result, ", node: ")
|
app(result, ", node: ")
|
||||||
app(result, debugTree(n.n, 2, 100))
|
app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
|
||||||
app(result, ")")
|
app(result, ")")
|
||||||
|
|
||||||
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
|
renderType=false): PRope =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
|
|
@ -425,6 +425,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||||
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
|
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
|
||||||
# [istr, symToYaml(n.sym, indent, maxRecDepth),
|
# [istr, symToYaml(n.sym, indent, maxRecDepth),
|
||||||
# toRope(n.sym.id)])
|
# toRope(n.sym.id)])
|
||||||
|
if renderType and n.sym.typ != nil:
|
||||||
|
appf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
|
||||||
of nkIdent:
|
of nkIdent:
|
||||||
if n.ident != nil:
|
if n.ident != nil:
|
||||||
appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
|
appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
|
||||||
|
|
@ -436,7 +438,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i],
|
appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i],
|
||||||
indent + 4, maxRecDepth - 1)])
|
indent + 4, maxRecDepth - 1, renderType)])
|
||||||
appf(result, "$N$1]", [istr])
|
appf(result, "$N$1]", [istr])
|
||||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [spaces(indent)])
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# c2nim - C to Nimrod source converter
|
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
import
|
|
||||||
strutils, os, times, parseopt, llstream, ast, renderer, options, msgs,
|
|
||||||
clex, cparse
|
|
||||||
|
|
||||||
const
|
|
||||||
Version = NimrodVersion
|
|
||||||
Usage = """
|
|
||||||
c2nim - C to Nimrod source converter
|
|
||||||
(c) 2013 Andreas Rumpf
|
|
||||||
Usage: c2nim [options] inputfile [options]
|
|
||||||
Options:
|
|
||||||
-o, --out:FILE set output filename
|
|
||||||
--cpp process C++ input file
|
|
||||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
|
||||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
|
||||||
--cdecl annotate procs with ``{.cdecl.}``
|
|
||||||
--stdcall annotate procs with ``{.stdcall.}``
|
|
||||||
--ref convert typ* to ref typ (default: ptr typ)
|
|
||||||
--prefix:PREFIX strip prefix for the generated Nimrod identifiers
|
|
||||||
(multiple --prefix options are supported)
|
|
||||||
--suffix:SUFFIX strip suffix for the generated Nimrod identifiers
|
|
||||||
(multiple --suffix options are supported)
|
|
||||||
--skipinclude do not convert ``#include`` to ``import``
|
|
||||||
--typeprefixes generate ``T`` and ``P`` type prefixes
|
|
||||||
--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 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)
|
|
||||||
result = parseUnit(p)
|
|
||||||
closeParser(p)
|
|
||||||
|
|
||||||
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
|
|
||||||
of cmdArgument: infile = key
|
|
||||||
of cmdLongOption, cmdShortOption:
|
|
||||||
case key.toLower
|
|
||||||
of "help", "h":
|
|
||||||
stdout.write(Usage)
|
|
||||||
quit(0)
|
|
||||||
of "version", "v":
|
|
||||||
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)
|
|
||||||
of cmdEnd: assert(false)
|
|
||||||
if infile.len == 0:
|
|
||||||
# no filename has been given, so we show the help:
|
|
||||||
stdout.write(Usage)
|
|
||||||
else:
|
|
||||||
if outfile.len == 0:
|
|
||||||
outfile = changeFileExt(infile, "nim")
|
|
||||||
infile = addFileExt(infile, "h")
|
|
||||||
main(infile, outfile, parserOptions, spliceHeader)
|
|
||||||
|
|
@ -1,787 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# c2nim - C to Nimrod source converter
|
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
# This module implements an Ansi C scanner. This is an adaption from
|
|
||||||
# the scanner module. Keywords are not handled here, but in the parser to make
|
|
||||||
# it more flexible.
|
|
||||||
|
|
||||||
|
|
||||||
import
|
|
||||||
options, msgs, strutils, platform, nimlexbase, llstream
|
|
||||||
|
|
||||||
const
|
|
||||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
|
||||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
|
||||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
|
|
||||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF'}
|
|
||||||
|
|
||||||
type
|
|
||||||
TTokKind* = enum
|
|
||||||
pxInvalid, pxEof,
|
|
||||||
pxMacroParam, # fake token: macro parameter (with its index)
|
|
||||||
pxStarComment, # /* */ comment
|
|
||||||
pxLineComment, # // comment
|
|
||||||
pxDirective, # #define, etc.
|
|
||||||
pxDirectiveParLe, # #define m( with parle (yes, C is that ugly!)
|
|
||||||
pxDirConc, # ##
|
|
||||||
pxNewLine, # newline: end of directive
|
|
||||||
pxAmp, # &
|
|
||||||
pxAmpAmp, # &&
|
|
||||||
pxAmpAsgn, # &=
|
|
||||||
pxAmpAmpAsgn, # &&=
|
|
||||||
pxBar, # |
|
|
||||||
pxBarBar, # ||
|
|
||||||
pxBarAsgn, # |=
|
|
||||||
pxBarBarAsgn, # ||=
|
|
||||||
pxNot, # !
|
|
||||||
pxPlusPlus, # ++
|
|
||||||
pxMinusMinus, # --
|
|
||||||
pxPlus, # +
|
|
||||||
pxPlusAsgn, # +=
|
|
||||||
pxMinus, # -
|
|
||||||
pxMinusAsgn, # -=
|
|
||||||
pxMod, # %
|
|
||||||
pxModAsgn, # %=
|
|
||||||
pxSlash, # /
|
|
||||||
pxSlashAsgn, # /=
|
|
||||||
pxStar, # *
|
|
||||||
pxStarAsgn, # *=
|
|
||||||
pxHat, # ^
|
|
||||||
pxHatAsgn, # ^=
|
|
||||||
pxAsgn, # =
|
|
||||||
pxEquals, # ==
|
|
||||||
pxDot, # .
|
|
||||||
pxDotDotDot, # ...
|
|
||||||
pxLe, # <=
|
|
||||||
pxLt, # <
|
|
||||||
pxGe, # >=
|
|
||||||
pxGt, # >
|
|
||||||
pxNeq, # !=
|
|
||||||
pxConditional, # ?
|
|
||||||
pxShl, # <<
|
|
||||||
pxShlAsgn, # <<=
|
|
||||||
pxShr, # >>
|
|
||||||
pxShrAsgn, # >>=
|
|
||||||
pxTilde, # ~
|
|
||||||
pxTildeAsgn, # ~=
|
|
||||||
pxArrow, # ->
|
|
||||||
pxScope, # ::
|
|
||||||
|
|
||||||
pxStrLit,
|
|
||||||
pxCharLit,
|
|
||||||
pxSymbol, # a symbol
|
|
||||||
pxIntLit,
|
|
||||||
pxInt64Lit, # long constant like 0x70fffffff or out of int range
|
|
||||||
pxFloatLit,
|
|
||||||
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
|
||||||
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
|
||||||
pxComma, pxSemiColon, pxColon,
|
|
||||||
pxAngleRi # '>' but determined to be the end of a
|
|
||||||
# template's angle bracket
|
|
||||||
TTokKinds* = set[TTokKind]
|
|
||||||
|
|
||||||
type
|
|
||||||
TNumericalBase* = enum base10, base2, base8, base16
|
|
||||||
TToken* = object
|
|
||||||
xkind*: TTokKind # the type of the token
|
|
||||||
s*: string # parsed symbol, char or string literal
|
|
||||||
iNumber*: BiggestInt # the parsed integer literal;
|
|
||||||
# if xkind == pxMacroParam: parameter's position
|
|
||||||
fNumber*: BiggestFloat # the parsed floating point literal
|
|
||||||
base*: TNumericalBase # the numerical base; only valid for int
|
|
||||||
# or float literals
|
|
||||||
next*: ref TToken # for C we need arbitrary look-ahead :-(
|
|
||||||
|
|
||||||
TLexer* = object of TBaseLexer
|
|
||||||
fileIdx*: int32
|
|
||||||
inDirective: bool
|
|
||||||
|
|
||||||
proc getTok*(L: var TLexer, tok: var TToken)
|
|
||||||
proc printTok*(tok: TToken)
|
|
||||||
proc `$`*(tok: TToken): string
|
|
||||||
# implementation
|
|
||||||
|
|
||||||
var
|
|
||||||
gLinesCompiled*: int
|
|
||||||
|
|
||||||
proc fillToken(L: var TToken) =
|
|
||||||
L.xkind = pxInvalid
|
|
||||||
L.iNumber = 0
|
|
||||||
L.s = ""
|
|
||||||
L.fNumber = 0.0
|
|
||||||
L.base = base10
|
|
||||||
|
|
||||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
|
||||||
openBaseLexer(lex, inputstream)
|
|
||||||
lex.fileIdx = filename.fileInfoIdx
|
|
||||||
|
|
||||||
proc closeLexer*(lex: var TLexer) =
|
|
||||||
inc(gLinesCompiled, lex.LineNumber)
|
|
||||||
closeBaseLexer(lex)
|
|
||||||
|
|
||||||
proc getColumn*(L: TLexer): int =
|
|
||||||
result = getColNumber(L, L.bufPos)
|
|
||||||
|
|
||||||
proc getLineInfo*(L: TLexer): TLineInfo =
|
|
||||||
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
|
|
||||||
|
|
||||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
|
||||||
msgs.GlobalError(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.GlobalError(info, msg, arg)
|
|
||||||
|
|
||||||
proc tokKindToStr*(k: TTokKind): string =
|
|
||||||
case k
|
|
||||||
of pxEof: result = "[EOF]"
|
|
||||||
of pxInvalid: result = "[invalid]"
|
|
||||||
of pxMacroParam: result = "[macro param]"
|
|
||||||
of pxStarComment, pxLineComment: result = "[comment]"
|
|
||||||
of pxStrLit: result = "[string literal]"
|
|
||||||
of pxCharLit: result = "[char literal]"
|
|
||||||
|
|
||||||
of pxDirective, pxDirectiveParLe: result = "#" # #define, etc.
|
|
||||||
of pxDirConc: result = "##"
|
|
||||||
of pxNewLine: result = "[NewLine]"
|
|
||||||
of pxAmp: result = "&" # &
|
|
||||||
of pxAmpAmp: result = "&&" # &&
|
|
||||||
of pxAmpAsgn: result = "&=" # &=
|
|
||||||
of pxAmpAmpAsgn: result = "&&=" # &&=
|
|
||||||
of pxBar: result = "|" # |
|
|
||||||
of pxBarBar: result = "||" # ||
|
|
||||||
of pxBarAsgn: result = "|=" # |=
|
|
||||||
of pxBarBarAsgn: result = "||=" # ||=
|
|
||||||
of pxNot: result = "!" # !
|
|
||||||
of pxPlusPlus: result = "++" # ++
|
|
||||||
of pxMinusMinus: result = "--" # --
|
|
||||||
of pxPlus: result = "+" # +
|
|
||||||
of pxPlusAsgn: result = "+=" # +=
|
|
||||||
of pxMinus: result = "-" # -
|
|
||||||
of pxMinusAsgn: result = "-=" # -=
|
|
||||||
of pxMod: result = "%" # %
|
|
||||||
of pxModAsgn: result = "%=" # %=
|
|
||||||
of pxSlash: result = "/" # /
|
|
||||||
of pxSlashAsgn: result = "/=" # /=
|
|
||||||
of pxStar: result = "*" # *
|
|
||||||
of pxStarAsgn: result = "*=" # *=
|
|
||||||
of pxHat: result = "^" # ^
|
|
||||||
of pxHatAsgn: result = "^=" # ^=
|
|
||||||
of pxAsgn: result = "=" # =
|
|
||||||
of pxEquals: result = "==" # ==
|
|
||||||
of pxDot: result = "." # .
|
|
||||||
of pxDotDotDot: result = "..." # ...
|
|
||||||
of pxLe: result = "<=" # <=
|
|
||||||
of pxLt: result = "<" # <
|
|
||||||
of pxGe: result = ">=" # >=
|
|
||||||
of pxGt: result = ">" # >
|
|
||||||
of pxNeq: result = "!=" # !=
|
|
||||||
of pxConditional: result = "?"
|
|
||||||
of pxShl: result = "<<"
|
|
||||||
of pxShlAsgn: result = "<<="
|
|
||||||
of pxShr: result = ">>"
|
|
||||||
of pxShrAsgn: result = ">>="
|
|
||||||
of pxTilde: result = "~"
|
|
||||||
of pxTildeAsgn: result = "~="
|
|
||||||
of pxArrow: result = "->"
|
|
||||||
of pxScope: result = "::"
|
|
||||||
|
|
||||||
of pxSymbol: result = "[identifier]"
|
|
||||||
of pxIntLit, pxInt64Lit: result = "[integer literal]"
|
|
||||||
of pxFloatLit: result = "[floating point literal]"
|
|
||||||
of pxParLe: result = "("
|
|
||||||
of pxParRi: result = ")"
|
|
||||||
of pxBracketLe: result = "["
|
|
||||||
of pxBracketRi: result = "]"
|
|
||||||
of pxComma: result = ","
|
|
||||||
of pxSemiColon: result = ";"
|
|
||||||
of pxColon: result = ":"
|
|
||||||
of pxCurlyLe: result = "{"
|
|
||||||
of pxCurlyRi: result = "}"
|
|
||||||
of pxAngleRi: result = "> [end of template]"
|
|
||||||
|
|
||||||
proc `$`(tok: TToken): string =
|
|
||||||
case tok.xkind
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc printTok(tok: TToken) =
|
|
||||||
writeln(stdout, $tok)
|
|
||||||
|
|
||||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
|
||||||
# matches ([chars]_)*
|
|
||||||
var pos = L.bufpos # use registers for pos, buf
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
if buf[pos] in chars:
|
|
||||||
add(tok.s, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
if buf[pos] == '_':
|
|
||||||
add(tok.s, '_')
|
|
||||||
inc(pos)
|
|
||||||
L.bufPos = pos
|
|
||||||
|
|
||||||
proc isFloatLiteral(s: string): bool =
|
|
||||||
for i in countup(0, len(s)-1):
|
|
||||||
if s[i] in {'.', 'e', 'E'}:
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 2 # skip 0b
|
|
||||||
tok.base = base2
|
|
||||||
var xi: BiggestInt = 0
|
|
||||||
var bits = 0
|
|
||||||
while true:
|
|
||||||
case L.buf[pos]
|
|
||||||
of 'A'..'Z', 'a'..'z':
|
|
||||||
# ignore type suffix:
|
|
||||||
inc(pos)
|
|
||||||
of '2'..'9', '.':
|
|
||||||
lexMessage(L, errInvalidNumber)
|
|
||||||
inc(pos)
|
|
||||||
of '_':
|
|
||||||
inc(pos)
|
|
||||||
of '0', '1':
|
|
||||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
inc(bits)
|
|
||||||
else: break
|
|
||||||
tok.iNumber = xi
|
|
||||||
if (bits > 32): tok.xkind = pxInt64Lit
|
|
||||||
else: tok.xkind = pxIntLit
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getNumber8(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 1 # skip 0
|
|
||||||
tok.base = base8
|
|
||||||
var xi: BiggestInt = 0
|
|
||||||
var bits = 0
|
|
||||||
while true:
|
|
||||||
case L.buf[pos]
|
|
||||||
of 'A'..'Z', 'a'..'z':
|
|
||||||
# ignore type suffix:
|
|
||||||
inc(pos)
|
|
||||||
of '8'..'9', '.':
|
|
||||||
lexMessage(L, errInvalidNumber)
|
|
||||||
inc(pos)
|
|
||||||
of '_':
|
|
||||||
inc(pos)
|
|
||||||
of '0'..'7':
|
|
||||||
xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
inc(bits)
|
|
||||||
else: break
|
|
||||||
tok.iNumber = xi
|
|
||||||
if (bits > 12): tok.xkind = pxInt64Lit
|
|
||||||
else: tok.xkind = pxIntLit
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 2 # skip 0x
|
|
||||||
tok.base = base16
|
|
||||||
var xi: BiggestInt = 0
|
|
||||||
var bits = 0
|
|
||||||
while true:
|
|
||||||
case L.buf[pos]
|
|
||||||
of 'G'..'Z', 'g'..'z':
|
|
||||||
# ignore type suffix:
|
|
||||||
inc(pos)
|
|
||||||
of '_': inc(pos)
|
|
||||||
of '0'..'9':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
of 'a'..'f':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
of 'A'..'F':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
else: break
|
|
||||||
tok.iNumber = xi
|
|
||||||
if bits > 32: tok.xkind = pxInt64Lit
|
|
||||||
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
|
|
||||||
if L.buf[L.bufpos] == '.':
|
|
||||||
add(tok.s, "0.")
|
|
||||||
inc(L.bufpos)
|
|
||||||
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)
|
|
||||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
|
||||||
tok.xkind = pxInt64Lit
|
|
||||||
else:
|
|
||||||
tok.xkind = pxIntLit
|
|
||||||
except EInvalidValue:
|
|
||||||
lexMessage(L, errInvalidNumber, tok.s)
|
|
||||||
except EOverflow:
|
|
||||||
lexMessage(L, errNumberOutOfRange, tok.s)
|
|
||||||
# ignore type suffix:
|
|
||||||
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
|
|
||||||
|
|
||||||
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)
|
|
||||||
else: result = pos
|
|
||||||
|
|
||||||
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
|
|
||||||
inc(L.bufpos) # skip \
|
|
||||||
case L.buf[L.bufpos]
|
|
||||||
of 'b', 'B':
|
|
||||||
add(tok.s, '\b')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of 't', 'T':
|
|
||||||
add(tok.s, '\t')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of 'n', 'N':
|
|
||||||
add(tok.s, '\L')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of 'f', 'F':
|
|
||||||
add(tok.s, '\f')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of 'r', 'R':
|
|
||||||
add(tok.s, '\r')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '\'':
|
|
||||||
add(tok.s, '\'')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '"':
|
|
||||||
add(tok.s, '"')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '\\':
|
|
||||||
add(tok.s, '\b')
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '0'..'7':
|
|
||||||
var xi = ord(L.buf[L.bufpos]) - ord('0')
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
|
||||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc getCharLit(L: var TLexer, tok: var TToken) =
|
|
||||||
inc(L.bufpos) # skip '
|
|
||||||
if L.buf[L.bufpos] == '\\':
|
|
||||||
escape(L, tok)
|
|
||||||
else:
|
|
||||||
add(tok.s, L.buf[L.bufpos])
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '\'':
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
lexMessage(L, errMissingFinalQuote)
|
|
||||||
tok.xkind = pxCharLit
|
|
||||||
|
|
||||||
proc getString(L: var TLexer, tok: var TToken) =
|
|
||||||
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
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of '\"':
|
|
||||||
inc(pos)
|
|
||||||
break
|
|
||||||
of CR:
|
|
||||||
pos = nimlexbase.HandleCR(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
of LF:
|
|
||||||
pos = nimlexbase.HandleLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
of nimlexbase.EndOfFile:
|
|
||||||
var line2 = L.linenumber
|
|
||||||
L.LineNumber = line
|
|
||||||
lexMessagePos(L, errClosingQuoteExpected, L.lineStart)
|
|
||||||
L.LineNumber = line2
|
|
||||||
break
|
|
||||||
of '\\':
|
|
||||||
# we allow an empty \ for line concatenation, but we don't require it
|
|
||||||
# for line concatenation
|
|
||||||
L.bufpos = pos
|
|
||||||
escape(L, tok, allowEmpty=true)
|
|
||||||
pos = L.bufpos
|
|
||||||
else:
|
|
||||||
add(tok.s, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
L.bufpos = pos
|
|
||||||
tok.xkind = pxStrLit
|
|
||||||
|
|
||||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
var c = buf[pos]
|
|
||||||
if c notin SymChars: break
|
|
||||||
add(tok.s, c)
|
|
||||||
inc(pos)
|
|
||||||
L.bufpos = pos
|
|
||||||
tok.xkind = pxSymbol
|
|
||||||
|
|
||||||
proc scanLineComment(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
# a comment ends if the next line does not start with the // on the same
|
|
||||||
# column after only whitespace
|
|
||||||
tok.xkind = pxLineComment
|
|
||||||
var col = getColNumber(L, pos)
|
|
||||||
while true:
|
|
||||||
inc(pos, 2) # skip //
|
|
||||||
add(tok.s, '#')
|
|
||||||
while not (buf[pos] in {CR, LF, nimlexbase.EndOfFile}):
|
|
||||||
add(tok.s, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
var indent = 0
|
|
||||||
while buf[pos] == ' ':
|
|
||||||
inc(pos)
|
|
||||||
inc(indent)
|
|
||||||
if (col == indent) and (buf[pos] == '/') and (buf[pos + 1] == '/'):
|
|
||||||
add(tok.s, "\n")
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc scanStarComment(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
tok.s = "#"
|
|
||||||
tok.xkind = pxStarComment
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of CR, LF:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
add(tok.s, "\n#")
|
|
||||||
# skip annoying stars as line prefix: (eg.
|
|
||||||
# /*
|
|
||||||
# * ugly comment <-- this star
|
|
||||||
# */
|
|
||||||
while buf[pos] in {' ', '\t'}:
|
|
||||||
add(tok.s, ' ')
|
|
||||||
inc(pos)
|
|
||||||
if buf[pos] == '*' and buf[pos+1] != '/': inc(pos)
|
|
||||||
of '*':
|
|
||||||
inc(pos)
|
|
||||||
if buf[pos] == '/':
|
|
||||||
inc(pos)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
add(tok.s, '*')
|
|
||||||
of nimlexbase.EndOfFile:
|
|
||||||
lexMessage(L, errTokenExpected, "*/")
|
|
||||||
else:
|
|
||||||
add(tok.s, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc skip(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of '\\':
|
|
||||||
# Ignore \ line continuation characters when not inDirective
|
|
||||||
inc(pos)
|
|
||||||
if L.inDirective:
|
|
||||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
|
||||||
if buf[pos] in {CR, LF}:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
of ' ', Tabulator:
|
|
||||||
inc(pos) # newline is special:
|
|
||||||
of CR, LF:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
if L.inDirective:
|
|
||||||
tok.xkind = pxNewLine
|
|
||||||
L.inDirective = false
|
|
||||||
else:
|
|
||||||
break # EndOfFile also leaves the loop
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getDirective(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 1
|
|
||||||
var buf = L.buf
|
|
||||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
|
||||||
while buf[pos] in SymChars:
|
|
||||||
add(tok.s, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
# a HACK: we need to distinguish
|
|
||||||
# #define x (...)
|
|
||||||
# from:
|
|
||||||
# #define x(...)
|
|
||||||
#
|
|
||||||
L.bufpos = pos
|
|
||||||
# look ahead:
|
|
||||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
|
||||||
while buf[pos] in SymChars: inc(pos)
|
|
||||||
if buf[pos] == '(': tok.xkind = pxDirectiveParLe
|
|
||||||
else: tok.xkind = pxDirective
|
|
||||||
L.inDirective = true
|
|
||||||
|
|
||||||
proc getTok(L: var TLexer, tok: var TToken) =
|
|
||||||
tok.xkind = pxInvalid
|
|
||||||
fillToken(tok)
|
|
||||||
skip(L, tok)
|
|
||||||
if tok.xkind == pxNewLine: return
|
|
||||||
var c = L.buf[L.bufpos]
|
|
||||||
if c in SymStartChars:
|
|
||||||
getSymbol(L, tok)
|
|
||||||
elif c == '0':
|
|
||||||
case L.buf[L.bufpos+1]
|
|
||||||
of 'x', 'X': getNumber16(L, tok)
|
|
||||||
of 'b', 'B': getNumber2(L, tok)
|
|
||||||
of '1'..'7': getNumber8(L, tok)
|
|
||||||
else: getNumber(L, tok)
|
|
||||||
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)
|
|
||||||
of '/':
|
|
||||||
if L.buf[L.bufpos + 1] == '/':
|
|
||||||
scanLineComment(L, tok)
|
|
||||||
elif L.buf[L.bufpos+1] == '*':
|
|
||||||
inc(L.bufpos, 2)
|
|
||||||
scanStarComment(L, tok)
|
|
||||||
elif L.buf[L.bufpos+1] == '=':
|
|
||||||
inc(L.bufpos, 2)
|
|
||||||
tok.xkind = pxSlashAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxSlash
|
|
||||||
inc(L.bufpos)
|
|
||||||
of ',':
|
|
||||||
tok.xkind = pxComma
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '(':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxParLe
|
|
||||||
of '*':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxStarAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxStar
|
|
||||||
of ')':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxParRi
|
|
||||||
of '[':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxBracketLe
|
|
||||||
of ']':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxBracketRi
|
|
||||||
of '.':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] == '.':
|
|
||||||
tok.xkind = pxDotDotDot
|
|
||||||
inc(L.bufpos, 2)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxDot
|
|
||||||
of '{':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxCurlyLe
|
|
||||||
of '}':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxCurlyRi
|
|
||||||
of '+':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxPlusAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
elif L.buf[L.bufpos] == '+':
|
|
||||||
tok.xkind = pxPlusPlus
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxPlus
|
|
||||||
of '-':
|
|
||||||
inc(L.bufpos)
|
|
||||||
case L.buf[L.bufpos]
|
|
||||||
of '>':
|
|
||||||
tok.xkind = pxArrow
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '=':
|
|
||||||
tok.xkind = pxMinusAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '-':
|
|
||||||
tok.xkind = pxMinusMinus
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxMinus
|
|
||||||
of '?':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxConditional
|
|
||||||
of ':':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == ':':
|
|
||||||
tok.xkind = pxScope
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxColon
|
|
||||||
of '!':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxNeq
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxNot
|
|
||||||
of '<':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxLe
|
|
||||||
elif L.buf[L.bufpos] == '<':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxShlAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxShl
|
|
||||||
else:
|
|
||||||
tok.xkind = pxLt
|
|
||||||
of '>':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxGe
|
|
||||||
elif L.buf[L.bufpos] == '>':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxShrAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxShr
|
|
||||||
else:
|
|
||||||
tok.xkind = pxGt
|
|
||||||
of '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxEquals
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxAsgn
|
|
||||||
of '&':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxAmpAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
elif L.buf[L.bufpos] == '&':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxAmpAmpAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxAmpAmp
|
|
||||||
else:
|
|
||||||
tok.xkind = pxAmp
|
|
||||||
of '|':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxBarAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
elif L.buf[L.bufpos] == '|':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxBarBarAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxBarBar
|
|
||||||
else:
|
|
||||||
tok.xkind = pxBar
|
|
||||||
of '^':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxHatAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxHat
|
|
||||||
of '%':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxModAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxMod
|
|
||||||
of '~':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
tok.xkind = pxTildeAsgn
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxTilde
|
|
||||||
of '#':
|
|
||||||
if L.buf[L.bufpos+1] == '#':
|
|
||||||
inc(L.bufpos, 2)
|
|
||||||
tok.xkind = pxDirConc
|
|
||||||
else:
|
|
||||||
getDirective(L, tok)
|
|
||||||
of '"': getString(L, tok)
|
|
||||||
of '\'': getCharLit(L, tok)
|
|
||||||
of nimlexbase.EndOfFile:
|
|
||||||
tok.xkind = pxEof
|
|
||||||
else:
|
|
||||||
tok.s = $c
|
|
||||||
tok.xkind = pxInvalid
|
|
||||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
|
||||||
inc(L.bufpos)
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,347 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# c2nim - C to Nimrod source converter
|
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Preprocessor support
|
|
||||||
|
|
||||||
const
|
|
||||||
c2nimSymbol = "C2NIM"
|
|
||||||
|
|
||||||
proc eatNewLine(p: var TParser, n: PNode) =
|
|
||||||
if p.tok.xkind == pxLineComment:
|
|
||||||
skipCom(p, n)
|
|
||||||
if p.tok.xkind == pxNewLine: getTok(p)
|
|
||||||
elif p.tok.xkind == pxNewLine:
|
|
||||||
eat(p, pxNewLine)
|
|
||||||
|
|
||||||
proc skipLine(p: var TParser) =
|
|
||||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
|
|
||||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
|
||||||
if p.tok.xkind == pxCurlyLe or
|
|
||||||
(p.tok.xkind == pxSymbol and (
|
|
||||||
declKeyword(p, p.tok.s) or stmtKeyword(p.tok.s))):
|
|
||||||
addSon(tmplDef, statement(p))
|
|
||||||
result = "stmt"
|
|
||||||
elif p.tok.xkind in {pxLineComment, pxNewLine}:
|
|
||||||
addSon(tmplDef, buildStmtList(newNodeP(nkNilLit, p)))
|
|
||||||
result = "stmt"
|
|
||||||
else:
|
|
||||||
addSon(tmplDef, buildStmtList(expression(p)))
|
|
||||||
result = "expr"
|
|
||||||
|
|
||||||
proc parseDefine(p: var TParser): PNode =
|
|
||||||
if p.tok.xkind == pxDirectiveParLe:
|
|
||||||
# a macro with parameters:
|
|
||||||
result = newNodeP(nkTemplateDef, p)
|
|
||||||
getTok(p)
|
|
||||||
addSon(result, skipIdentExport(p))
|
|
||||||
addSon(result, ast.emptyNode)
|
|
||||||
eat(p, pxParLe)
|
|
||||||
var params = newNodeP(nkFormalParams, p)
|
|
||||||
# return type; not known yet:
|
|
||||||
addSon(params, ast.emptyNode)
|
|
||||||
if p.tok.xkind != pxParRi:
|
|
||||||
var identDefs = newNodeP(nkIdentDefs, p)
|
|
||||||
while p.tok.xkind != pxParRi:
|
|
||||||
addSon(identDefs, skipIdent(p))
|
|
||||||
skipStarCom(p, nil)
|
|
||||||
if p.tok.xkind != pxComma: break
|
|
||||||
getTok(p)
|
|
||||||
addSon(identDefs, newIdentNodeP("expr", p))
|
|
||||||
addSon(identDefs, ast.emptyNode)
|
|
||||||
addSon(params, identDefs)
|
|
||||||
eat(p, pxParRi)
|
|
||||||
|
|
||||||
addSon(result, ast.emptyNode) # no generic parameters
|
|
||||||
addSon(result, params)
|
|
||||||
addSon(result, ast.emptyNode) # no pragmas
|
|
||||||
addSon(result, ast.emptyNode)
|
|
||||||
var kind = parseDefineBody(p, result)
|
|
||||||
params.sons[0] = newIdentNodeP(kind, p)
|
|
||||||
eatNewLine(p, result)
|
|
||||||
else:
|
|
||||||
# a macro without parameters:
|
|
||||||
result = newNodeP(nkConstSection, p)
|
|
||||||
while p.tok.xkind == pxDirective and p.tok.s == "define":
|
|
||||||
getTok(p) # skip #define
|
|
||||||
var c = newNodeP(nkConstDef, p)
|
|
||||||
addSon(c, skipIdentExport(p))
|
|
||||||
addSon(c, ast.emptyNode)
|
|
||||||
skipStarCom(p, c)
|
|
||||||
if p.tok.xkind in {pxLineComment, pxNewLine, pxEof}:
|
|
||||||
addSon(c, newIdentNodeP("true", p))
|
|
||||||
else:
|
|
||||||
addSon(c, expression(p))
|
|
||||||
addSon(result, c)
|
|
||||||
eatNewLine(p, c)
|
|
||||||
assert result != nil
|
|
||||||
|
|
||||||
proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
|
|
||||||
m.body = @[]
|
|
||||||
# A little hack: We safe the context, so that every following token will be
|
|
||||||
# put into a newly allocated TToken object. Thus we can just save a
|
|
||||||
# reference to the token in the macro's body.
|
|
||||||
saveContext(p)
|
|
||||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}:
|
|
||||||
case p.tok.xkind
|
|
||||||
of pxSymbol:
|
|
||||||
# is it a parameter reference?
|
|
||||||
var tok = p.tok
|
|
||||||
for i in 0..high(params):
|
|
||||||
if params[i] == p.tok.s:
|
|
||||||
new(tok)
|
|
||||||
tok.xkind = pxMacroParam
|
|
||||||
tok.iNumber = i
|
|
||||||
break
|
|
||||||
m.body.add(tok)
|
|
||||||
of pxDirConc:
|
|
||||||
# just ignore this token: this implements token merging correctly
|
|
||||||
discard
|
|
||||||
else:
|
|
||||||
m.body.add(p.tok)
|
|
||||||
# we do not want macro expansion here:
|
|
||||||
rawGetTok(p)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
closeContext(p)
|
|
||||||
# newline token might be overwritten, but this is not
|
|
||||||
# part of the macro body, so it is safe.
|
|
||||||
|
|
||||||
proc parseDef(p: var TParser, m: var TMacro) =
|
|
||||||
var hasParams = p.tok.xkind == pxDirectiveParLe
|
|
||||||
getTok(p)
|
|
||||||
expectIdent(p)
|
|
||||||
m.name = p.tok.s
|
|
||||||
getTok(p)
|
|
||||||
var params: seq[string] = @[]
|
|
||||||
# parse parameters:
|
|
||||||
if hasParams:
|
|
||||||
eat(p, pxParLe)
|
|
||||||
while p.tok.xkind != pxParRi:
|
|
||||||
expectIdent(p)
|
|
||||||
params.add(p.tok.s)
|
|
||||||
getTok(p)
|
|
||||||
skipStarCom(p, nil)
|
|
||||||
if p.tok.xkind != pxComma: break
|
|
||||||
getTok(p)
|
|
||||||
eat(p, pxParRi)
|
|
||||||
m.params = params.len
|
|
||||||
parseDefBody(p, m, params)
|
|
||||||
|
|
||||||
proc isDir(p: TParser, dir: string): bool =
|
|
||||||
result = p.tok.xkind in {pxDirectiveParLe, pxDirective} and p.tok.s == dir
|
|
||||||
|
|
||||||
proc parseInclude(p: var TParser): PNode =
|
|
||||||
result = newNodeP(nkImportStmt, p)
|
|
||||||
while isDir(p, "include"):
|
|
||||||
getTok(p) # skip "include"
|
|
||||||
if p.tok.xkind == pxStrLit and pfSkipInclude notin p.options.flags:
|
|
||||||
var file = newStrNodeP(nkStrLit, changeFileExt(p.tok.s, ""), p)
|
|
||||||
addSon(result, file)
|
|
||||||
getTok(p)
|
|
||||||
skipStarCom(p, file)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
else:
|
|
||||||
skipLine(p)
|
|
||||||
if sonsLen(result) == 0:
|
|
||||||
# we only parsed includes that we chose to ignore:
|
|
||||||
result = ast.emptyNode
|
|
||||||
|
|
||||||
proc definedExprAux(p: var TParser): PNode =
|
|
||||||
result = newNodeP(nkCall, p)
|
|
||||||
addSon(result, newIdentNodeP("defined", p))
|
|
||||||
addSon(result, skipIdent(p))
|
|
||||||
|
|
||||||
proc parseStmtList(p: var TParser): PNode =
|
|
||||||
result = newNodeP(nkStmtList, p)
|
|
||||||
while true:
|
|
||||||
case p.tok.xkind
|
|
||||||
of pxEof: break
|
|
||||||
of pxDirectiveParLe, pxDirective:
|
|
||||||
case p.tok.s
|
|
||||||
of "else", "endif", "elif": break
|
|
||||||
else: discard
|
|
||||||
addSon(result, statement(p))
|
|
||||||
|
|
||||||
proc eatEndif(p: var TParser) =
|
|
||||||
if isDir(p, "endif"):
|
|
||||||
skipLine(p)
|
|
||||||
else:
|
|
||||||
parMessage(p, errXExpected, "#endif")
|
|
||||||
|
|
||||||
proc parseIfDirAux(p: var TParser, result: PNode) =
|
|
||||||
addSon(result.sons[0], parseStmtList(p))
|
|
||||||
while isDir(p, "elif"):
|
|
||||||
var b = newNodeP(nkElifBranch, p)
|
|
||||||
getTok(p)
|
|
||||||
addSon(b, expression(p))
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
addSon(b, parseStmtList(p))
|
|
||||||
addSon(result, b)
|
|
||||||
if isDir(p, "else"):
|
|
||||||
var s = newNodeP(nkElse, p)
|
|
||||||
skipLine(p)
|
|
||||||
addSon(s, parseStmtList(p))
|
|
||||||
addSon(result, s)
|
|
||||||
eatEndif(p)
|
|
||||||
|
|
||||||
proc skipUntilEndif(p: var TParser) =
|
|
||||||
var nested = 1
|
|
||||||
while p.tok.xkind != pxEof:
|
|
||||||
if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"):
|
|
||||||
inc(nested)
|
|
||||||
elif isDir(p, "endif"):
|
|
||||||
dec(nested)
|
|
||||||
if nested <= 0:
|
|
||||||
skipLine(p)
|
|
||||||
return
|
|
||||||
getTok(p)
|
|
||||||
parMessage(p, errXExpected, "#endif")
|
|
||||||
|
|
||||||
type
|
|
||||||
TEndifMarker = enum
|
|
||||||
emElif, emElse, emEndif
|
|
||||||
|
|
||||||
proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =
|
|
||||||
var nested = 1
|
|
||||||
while p.tok.xkind != pxEof:
|
|
||||||
if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"):
|
|
||||||
inc(nested)
|
|
||||||
elif isDir(p, "elif") and nested <= 1:
|
|
||||||
return emElif
|
|
||||||
elif isDir(p, "else") and nested <= 1:
|
|
||||||
return emElse
|
|
||||||
elif isDir(p, "endif"):
|
|
||||||
dec(nested)
|
|
||||||
if nested <= 0:
|
|
||||||
return emEndif
|
|
||||||
getTok(p)
|
|
||||||
parMessage(p, errXExpected, "#endif")
|
|
||||||
|
|
||||||
proc parseIfdef(p: var TParser): PNode =
|
|
||||||
getTok(p) # skip #ifdef
|
|
||||||
expectIdent(p)
|
|
||||||
case p.tok.s
|
|
||||||
of "__cplusplus":
|
|
||||||
skipUntilEndif(p)
|
|
||||||
result = ast.emptyNode
|
|
||||||
of c2nimSymbol:
|
|
||||||
skipLine(p)
|
|
||||||
result = parseStmtList(p)
|
|
||||||
skipUntilEndif(p)
|
|
||||||
else:
|
|
||||||
result = newNodeP(nkWhenStmt, p)
|
|
||||||
addSon(result, newNodeP(nkElifBranch, p))
|
|
||||||
addSon(result.sons[0], definedExprAux(p))
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
parseIfDirAux(p, result)
|
|
||||||
|
|
||||||
proc parseIfndef(p: var TParser): PNode =
|
|
||||||
result = ast.emptyNode
|
|
||||||
getTok(p) # skip #ifndef
|
|
||||||
expectIdent(p)
|
|
||||||
if p.tok.s == c2nimSymbol:
|
|
||||||
skipLine(p)
|
|
||||||
case skipUntilElifElseEndif(p)
|
|
||||||
of emElif:
|
|
||||||
result = newNodeP(nkWhenStmt, p)
|
|
||||||
addSon(result, newNodeP(nkElifBranch, p))
|
|
||||||
getTok(p)
|
|
||||||
addSon(result.sons[0], expression(p))
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
parseIfDirAux(p, result)
|
|
||||||
of emElse:
|
|
||||||
skipLine(p)
|
|
||||||
result = parseStmtList(p)
|
|
||||||
eatEndif(p)
|
|
||||||
of emEndif: skipLine(p)
|
|
||||||
else:
|
|
||||||
result = newNodeP(nkWhenStmt, p)
|
|
||||||
addSon(result, newNodeP(nkElifBranch, p))
|
|
||||||
var e = newNodeP(nkCall, p)
|
|
||||||
addSon(e, newIdentNodeP("not", p))
|
|
||||||
addSon(e, definedExprAux(p))
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
addSon(result.sons[0], e)
|
|
||||||
parseIfDirAux(p, result)
|
|
||||||
|
|
||||||
proc parseIfDir(p: var TParser): PNode =
|
|
||||||
result = newNodeP(nkWhenStmt, p)
|
|
||||||
addSon(result, newNodeP(nkElifBranch, p))
|
|
||||||
getTok(p)
|
|
||||||
addSon(result.sons[0], expression(p))
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
parseIfDirAux(p, result)
|
|
||||||
|
|
||||||
proc parsePegLit(p: var TParser): TPeg =
|
|
||||||
var col = getColumn(p.lex) + 2
|
|
||||||
getTok(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,
|
|
||||||
line = p.lex.linenumber,
|
|
||||||
col = col)
|
|
||||||
getTok(p)
|
|
||||||
except EInvalidPeg:
|
|
||||||
parMessage(p, errUser, getCurrentExceptionMsg())
|
|
||||||
|
|
||||||
proc parseMangleDir(p: var TParser) =
|
|
||||||
var pattern = parsePegLit(p)
|
|
||||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
|
||||||
p.options.mangleRules.add((pattern, p.tok.s))
|
|
||||||
getTok(p)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
|
|
||||||
proc modulePragmas(p: var TParser): PNode =
|
|
||||||
if p.options.dynlibSym.len > 0 and not p.hasDeadCodeElimPragma:
|
|
||||||
p.hasDeadCodeElimPragma = true
|
|
||||||
result = newNodeP(nkPragma, p)
|
|
||||||
var e = newNodeP(nkExprColonExpr, p)
|
|
||||||
addSon(e, newIdentNodeP("deadCodeElim", p), newIdentNodeP("on", p))
|
|
||||||
addSon(result, e)
|
|
||||||
else:
|
|
||||||
result = ast.emptyNode
|
|
||||||
|
|
||||||
proc parseDir(p: var TParser): PNode =
|
|
||||||
result = ast.emptyNode
|
|
||||||
assert(p.tok.xkind in {pxDirective, pxDirectiveParLe})
|
|
||||||
case p.tok.s
|
|
||||||
of "define": result = parseDefine(p)
|
|
||||||
of "include": result = parseInclude(p)
|
|
||||||
of "ifdef": result = parseIfdef(p)
|
|
||||||
of "ifndef": result = parseIfndef(p)
|
|
||||||
of "if": result = parseIfDir(p)
|
|
||||||
of "cdecl", "stdcall", "ref", "skipinclude", "typeprefixes", "skipcomments":
|
|
||||||
discard setOption(p.options, p.tok.s)
|
|
||||||
getTok(p)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
of "dynlib", "header", "prefix", "suffix", "class":
|
|
||||||
var key = p.tok.s
|
|
||||||
getTok(p)
|
|
||||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
|
||||||
discard setOption(p.options, key, p.tok.s)
|
|
||||||
getTok(p)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
result = modulePragmas(p)
|
|
||||||
of "mangle":
|
|
||||||
parseMangleDir(p)
|
|
||||||
of "def":
|
|
||||||
var L = p.options.macros.len
|
|
||||||
setLen(p.options.macros, L+1)
|
|
||||||
parseDef(p, p.options.macros[L])
|
|
||||||
of "private":
|
|
||||||
var pattern = parsePegLit(p)
|
|
||||||
p.options.privateRules.add(pattern)
|
|
||||||
eatNewLine(p, nil)
|
|
||||||
else:
|
|
||||||
# ignore unimportant/unknown directive ("undef", "pragma", "error")
|
|
||||||
skipLine(p)
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# Use the modules of the compiler
|
|
||||||
|
|
||||||
path: "$nimrod/compiler"
|
|
||||||
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
enum vehicles
|
|
||||||
{
|
|
||||||
car = 0x10,
|
|
||||||
truck,
|
|
||||||
boat = 0x01,
|
|
||||||
ship = 1,
|
|
||||||
speedboat = 1,
|
|
||||||
bicycle = 4,
|
|
||||||
bobycar
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
red = 4,
|
|
||||||
green = 2,
|
|
||||||
blue
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum food
|
|
||||||
{
|
|
||||||
bread = 4,
|
|
||||||
toast = 4,
|
|
||||||
bun = 0x04,
|
|
||||||
cucumber = 2,
|
|
||||||
chocolate = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum numbers
|
|
||||||
{
|
|
||||||
one = 1,
|
|
||||||
two,
|
|
||||||
nten = - 10,
|
|
||||||
nnine,
|
|
||||||
four = 4,
|
|
||||||
three = + 3,
|
|
||||||
positivenine = + 9,
|
|
||||||
nfour = - 4,
|
|
||||||
negativeten = -10
|
|
||||||
};
|
|
||||||
|
|
@ -1,240 +0,0 @@
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Name: wx/matrix.h
|
|
||||||
// Purpose: wxTransformMatrix class. NOT YET USED
|
|
||||||
// Author: Chris Breeze, Julian Smart
|
|
||||||
// Modified by: Klaas Holwerda
|
|
||||||
// Created: 01/02/97
|
|
||||||
// RCS-ID: $Id$
|
|
||||||
// Copyright: (c) Julian Smart, Chris Breeze
|
|
||||||
// Licence: wxWindows licence
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef _WX_MATRIXH__
|
|
||||||
#define _WX_MATRIXH__
|
|
||||||
|
|
||||||
//! headerfiles="matrix.h wx/object.h"
|
|
||||||
#include "wx/object.h"
|
|
||||||
#include "wx/math.h"
|
|
||||||
|
|
||||||
//! codefiles="matrix.cpp"
|
|
||||||
|
|
||||||
// A simple 3x3 matrix. This may be replaced by a more general matrix
|
|
||||||
// class some day.
|
|
||||||
//
|
|
||||||
// Note: this is intended to be used in wxDC at some point to replace
|
|
||||||
// the current system of scaling/translation. It is not yet used.
|
|
||||||
|
|
||||||
#def WXDLLIMPEXP_CORE
|
|
||||||
#header "wxmatrix.h"
|
|
||||||
|
|
||||||
//:definition
|
|
||||||
// A 3x3 matrix to do 2D transformations.
|
|
||||||
// It can be used to map data to window coordinates,
|
|
||||||
// and also for manipulating your own data.
|
|
||||||
// For example drawing a picture (composed of several primitives)
|
|
||||||
// at a certain coordinate and angle within another parent picture.
|
|
||||||
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
|
|
||||||
// It is used where possible to optimize calculations.
|
|
||||||
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
wxTransformMatrix(void);
|
|
||||||
wxTransformMatrix(const wxTransformMatrix& mat);
|
|
||||||
|
|
||||||
~wxTransformMatrix(void);
|
|
||||||
|
|
||||||
//get the value in the matrix at col,row
|
|
||||||
//rows are horizontal (second index of m_matrix member)
|
|
||||||
//columns are vertical (first index of m_matrix member)
|
|
||||||
double GetValue(int col, int row) const;
|
|
||||||
|
|
||||||
//set the value in the matrix at col,row
|
|
||||||
//rows are horizontal (second index of m_matrix member)
|
|
||||||
//columns are vertical (first index of m_matrix member)
|
|
||||||
void SetValue(int col, int row, double value);
|
|
||||||
|
|
||||||
void operator = (const wxTransformMatrix& mat);
|
|
||||||
bool operator == (const wxTransformMatrix& mat) const;
|
|
||||||
bool operator != (const module::gah::wxTransformMatrix& mat) const;
|
|
||||||
|
|
||||||
//multiply every element by t
|
|
||||||
wxTransformMatrix& operator*=(const double& t);
|
|
||||||
//divide every element by t
|
|
||||||
wxTransformMatrix& operator/=(const double& t);
|
|
||||||
//add matrix m to this t
|
|
||||||
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
|
|
||||||
//subtract matrix m from this
|
|
||||||
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
|
|
||||||
//multiply matrix m with this
|
|
||||||
wxTransformMatrix& operator*=(const wxTransformMatrix& m);
|
|
||||||
|
|
||||||
// constant operators
|
|
||||||
|
|
||||||
//multiply every element by t and return result
|
|
||||||
wxTransformMatrix operator*(const double& t) const;
|
|
||||||
//divide this matrix by t and return result
|
|
||||||
wxTransformMatrix operator/(const double& t) const;
|
|
||||||
//add matrix m to this and return result
|
|
||||||
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
|
|
||||||
//subtract matrix m from this and return result
|
|
||||||
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
|
|
||||||
//multiply this by matrix m and return result
|
|
||||||
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
|
|
||||||
wxTransformMatrix operator-() const;
|
|
||||||
|
|
||||||
//rows are horizontal (second index of m_matrix member)
|
|
||||||
//columns are vertical (first index of m_matrix member)
|
|
||||||
double& operator()(int col, int row);
|
|
||||||
|
|
||||||
//rows are horizontal (second index of m_matrix member)
|
|
||||||
//columns are vertical (first index of m_matrix member)
|
|
||||||
double operator()(int col, int row) const;
|
|
||||||
|
|
||||||
// Invert matrix
|
|
||||||
bool Invert(void);
|
|
||||||
|
|
||||||
// Make into identity matrix
|
|
||||||
bool Identity(void);
|
|
||||||
|
|
||||||
// Is the matrix the identity matrix?
|
|
||||||
// Only returns a flag, which is set whenever an operation
|
|
||||||
// is done.
|
|
||||||
inline bool IsIdentity(void) const { return m_isIdentity; }
|
|
||||||
|
|
||||||
// This does an actual check.
|
|
||||||
inline bool IsIdentity1(void) const ;
|
|
||||||
|
|
||||||
//Scale by scale (isotropic scaling i.e. the same in x and y):
|
|
||||||
//!ex:
|
|
||||||
//!code: | scale 0 0 |
|
|
||||||
//!code: matrix' = | 0 scale 0 | x matrix
|
|
||||||
//!code: | 0 0 scale |
|
|
||||||
bool Scale(double scale);
|
|
||||||
|
|
||||||
//Scale with center point and x/y scale
|
|
||||||
//
|
|
||||||
//!ex:
|
|
||||||
//!code: | xs 0 xc(1-xs) |
|
|
||||||
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
|
|
||||||
//!code: | 0 0 1 |
|
|
||||||
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);
|
|
||||||
|
|
||||||
// mirror a matrix in x, y
|
|
||||||
//!ex:
|
|
||||||
//!code: | -1 0 0 |
|
|
||||||
//!code: matrix' = | 0 -1 0 | x matrix
|
|
||||||
//!code: | 0 0 1 |
|
|
||||||
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
|
|
||||||
// Translate by dx, dy:
|
|
||||||
//!ex:
|
|
||||||
//!code: | 1 0 dx |
|
|
||||||
//!code: matrix' = | 0 1 dy | x matrix
|
|
||||||
//!code: | 0 0 1 |
|
|
||||||
bool Translate(double x, double y);
|
|
||||||
|
|
||||||
// Rotate clockwise by the given number of degrees:
|
|
||||||
//!ex:
|
|
||||||
//!code: | cos sin 0 |
|
|
||||||
//!code: matrix' = | -sin cos 0 | x matrix
|
|
||||||
//!code: | 0 0 1 |
|
|
||||||
bool Rotate(double angle);
|
|
||||||
|
|
||||||
//Rotate counter clockwise with point of rotation
|
|
||||||
//
|
|
||||||
//!ex:
|
|
||||||
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
|
|
||||||
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
|
|
||||||
//!code: | 0 0 1 |
|
|
||||||
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);
|
|
||||||
|
|
||||||
// Transform X value from logical to device
|
|
||||||
inline double TransformX(double x) const;
|
|
||||||
|
|
||||||
// Transform Y value from logical to device
|
|
||||||
inline double TransformY(double y) const;
|
|
||||||
|
|
||||||
// Transform a point from logical to device coordinates
|
|
||||||
bool TransformPoint(double x, double y, double& tx, double& ty) const;
|
|
||||||
|
|
||||||
// Transform a point from device to logical coordinates.
|
|
||||||
// Example of use:
|
|
||||||
// wxTransformMatrix mat = dc.GetTransformation();
|
|
||||||
// mat.Invert();
|
|
||||||
// mat.InverseTransformPoint(x, y, x1, y1);
|
|
||||||
// OR (shorthand:)
|
|
||||||
// dc.LogicalToDevice(x, y, x1, y1);
|
|
||||||
// The latter is slightly less efficient if we're doing several
|
|
||||||
// conversions, since the matrix is inverted several times.
|
|
||||||
// N.B. 'this' matrix is the inverse at this point
|
|
||||||
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;
|
|
||||||
|
|
||||||
double Get_scaleX();
|
|
||||||
double Get_scaleY();
|
|
||||||
double GetRotation();
|
|
||||||
void SetRotation(double rotation);
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
double m_matrix[3][3];
|
|
||||||
bool m_isIdentity;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Chris Breeze reported, that
|
|
||||||
some functions of wxTransformMatrix cannot work because it is not
|
|
||||||
known if he matrix has been inverted. Be careful when using it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Transform X value from logical to device
|
|
||||||
// warning: this function can only be used for this purpose
|
|
||||||
// because no rotation is involved when mapping logical to device coordinates
|
|
||||||
// mirror and scaling for x and y will be part of the matrix
|
|
||||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
|
||||||
// it in the logical coordinate system, use TransformPoint
|
|
||||||
inline double wxTransformMatrix::TransformX(double x) const
|
|
||||||
{
|
|
||||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
|
||||||
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
|
|
||||||
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
|
|
||||||
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform Y value from logical to device
|
|
||||||
// warning: this function can only be used for this purpose
|
|
||||||
// because no rotation is involved when mapping logical to device coordinates
|
|
||||||
// mirror and scaling for x and y will be part of the matrix
|
|
||||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
|
||||||
// it in the logical coordinate system, use TransformPoint
|
|
||||||
inline double wxTransformMatrix::TransformY(double y) const
|
|
||||||
{
|
|
||||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
|
||||||
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
|
|
||||||
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
|
|
||||||
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Is the matrix the identity matrix?
|
|
||||||
// Each operation checks whether the result is still the identity matrix and sets a flag.
|
|
||||||
inline bool wxTransformMatrix::IsIdentity1(void) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[1][1], 1.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[2][2], 1.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[1][0], 0.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[2][0], 0.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[0][1], 0.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[2][1], 0.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[0][2], 0.0) &&
|
|
||||||
wxIsSameDouble(m_matrix[1][2], 0.0) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculates the determinant of a 2 x 2 matrix
|
|
||||||
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
|
|
||||||
{
|
|
||||||
return a11 * a22 - a12 * a21;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _WX_MATRIXH__
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
struct normal{
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct outerStruct {
|
|
||||||
struct normal a_nomal_one;
|
|
||||||
|
|
||||||
int a;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
int b;
|
|
||||||
} a_union_in_the_struct;
|
|
||||||
|
|
||||||
int c;
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
int d;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int e;
|
|
||||||
} a_struct_in_the_union;
|
|
||||||
} a_union;
|
|
||||||
};
|
|
||||||
|
|
@ -1,622 +0,0 @@
|
||||||
/* This file has been written by Blablub.
|
|
||||||
*
|
|
||||||
* Another comment line.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
# ifdef __SOME_OTHER_CRAP
|
|
||||||
extern "C" {
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define interrupts() sei()
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* 8bit, color or not */
|
|
||||||
CV_LOAD_IMAGE_UNCHANGED =-1,
|
|
||||||
/* 8bit, gray */
|
|
||||||
CV_LOAD_IMAGE_GRAYSCALE =0,
|
|
||||||
/* ?, color */
|
|
||||||
CV_LOAD_IMAGE_COLOR =1,
|
|
||||||
/* any depth, ? */
|
|
||||||
CV_LOAD_IMAGE_ANYDEPTH =2,
|
|
||||||
/* ?, any color */
|
|
||||||
CV_LOAD_IMAGE_ANYCOLOR =4
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*callback_t) (int rc);
|
|
||||||
typedef const char* (*callback2)(int rc, long L, const char* buffer);
|
|
||||||
|
|
||||||
int aw_callback_set (AW_CALLBACK c, callback_t callback );
|
|
||||||
int aw_instance_callback_set (AW_CALLBACK c, callback_t callback);
|
|
||||||
|
|
||||||
unsigned long int wawa;
|
|
||||||
|
|
||||||
#define MAX(x, y) ((x) < (y)? (y) : (x))
|
|
||||||
|
|
||||||
#define AW_BUILD 85 // AW 5.0
|
|
||||||
// Limits
|
|
||||||
#define AW_MAX_AVCHANGE_PER_SECOND 10
|
|
||||||
|
|
||||||
#private expatDll
|
|
||||||
|
|
||||||
#if !defined(expatDll)
|
|
||||||
# if defined(windows)
|
|
||||||
# define expatDll "expat.dll"
|
|
||||||
# elif defined(macosx)
|
|
||||||
# define expatDll "libexpat.dynlib"
|
|
||||||
# else
|
|
||||||
# define expatDll "libexpat.so(.1|)"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#mangle "'XML_'{.*}" "$1"
|
|
||||||
#private "'XML_ParserStruct'"
|
|
||||||
|
|
||||||
#mangle cuint cint
|
|
||||||
|
|
||||||
unsigned int uiVar;
|
|
||||||
|
|
||||||
#private "@('_'!.)"
|
|
||||||
unsigned int myPrivateVar__;
|
|
||||||
|
|
||||||
|
|
||||||
struct XML_ParserStruct;
|
|
||||||
|
|
||||||
#def XMLCALL __cdecl
|
|
||||||
|
|
||||||
typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
|
|
||||||
const XML_Char *name,
|
|
||||||
XML_Content *model);
|
|
||||||
|
|
||||||
|
|
||||||
void* x;
|
|
||||||
void* fn(void);
|
|
||||||
void (*fn)(void);
|
|
||||||
void* (*fn)(void);
|
|
||||||
void* (*fn)(void*);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Very ugly real world code ahead:
|
|
||||||
*/
|
|
||||||
|
|
||||||
#def JMETHOD(rettype, name, params) rettype (*name) params
|
|
||||||
|
|
||||||
typedef struct cjpeg_source_struct * cjpeg_source_ptr;
|
|
||||||
|
|
||||||
struct cjpeg_source_struct {
|
|
||||||
JMETHOD(void, start_input, (j_compress_ptr cinfo,
|
|
||||||
cjpeg_source_ptr sinfo));
|
|
||||||
JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
|
|
||||||
cjpeg_source_ptr sinfo));
|
|
||||||
JMETHOD(void, finish_input, (j_compress_ptr cinfo,
|
|
||||||
cjpeg_source_ptr sinfo));
|
|
||||||
|
|
||||||
FILE *input_file;
|
|
||||||
|
|
||||||
JSAMPARRAY buffer;
|
|
||||||
JDIMENSION buffer_height;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test standalone structs:
|
|
||||||
|
|
||||||
union myunion {
|
|
||||||
char x, y, *z;
|
|
||||||
myint a, b;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
struct mystruct {
|
|
||||||
char x, y, *z;
|
|
||||||
myint a, b;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mystruct fn(i32 x, i64 y);
|
|
||||||
|
|
||||||
struct mystruct {
|
|
||||||
char x, y, *z;
|
|
||||||
myint a, b;
|
|
||||||
} *myvar = NULL, **myvar2 = NULL;
|
|
||||||
|
|
||||||
// anonymous struct:
|
|
||||||
|
|
||||||
struct {
|
|
||||||
char x, y, *z;
|
|
||||||
myint a, b;
|
|
||||||
} varX, **varY;
|
|
||||||
|
|
||||||
// empty anonymous struct:
|
|
||||||
|
|
||||||
struct {
|
|
||||||
|
|
||||||
} varX, **varY;
|
|
||||||
|
|
||||||
// Test C2NIM skipping:
|
|
||||||
|
|
||||||
#define MASK(x) ((x) & 0xff)
|
|
||||||
#define CAST1(x) ((int) &x)
|
|
||||||
#define CAST2(x) (typ*) &x
|
|
||||||
#define CAST3(x) ((const unsigned char**) &x)
|
|
||||||
|
|
||||||
#ifndef C2NIM
|
|
||||||
#if someNestedCond
|
|
||||||
This is an invalid text that should generate a parser error, if not
|
|
||||||
#endif
|
|
||||||
skipped correctly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef C2NIM
|
|
||||||
#if someNestedCond
|
|
||||||
This is an invalid text that should generate a parser error, if not
|
|
||||||
#endif
|
|
||||||
skipped correctly.
|
|
||||||
#else
|
|
||||||
typedef char gchar;
|
|
||||||
typedef unsigned int gunsignedint;
|
|
||||||
typedef unsigned char guchar;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# mangle "'those'" "these"
|
|
||||||
int those;
|
|
||||||
#elif abc
|
|
||||||
#if someNestedCond
|
|
||||||
This is an invalid text that should generate a parser error, if not
|
|
||||||
#else
|
|
||||||
skipped correctly.
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
Another crappy input line.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
point* newPoint(void) {
|
|
||||||
for (int i = 0; i < 89; ++i) echo("test" " string " "concatenation");
|
|
||||||
for (; j < 54; j++) {}
|
|
||||||
for (;; j--) ;
|
|
||||||
for (;;) {}
|
|
||||||
mytype * x = y * z;
|
|
||||||
|
|
||||||
if (**p == ' ') {
|
|
||||||
--p;
|
|
||||||
} else if (**p == '\t') {
|
|
||||||
p += 3;
|
|
||||||
} else {
|
|
||||||
p = 45 + (mytype*)45;
|
|
||||||
p = 45 + ((mytype*)45);
|
|
||||||
p = 45 + ((mytype)45);
|
|
||||||
// BUG: This does not parse:
|
|
||||||
// p = 45 + (mytype)45;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (x >= 6 && x <= 20)
|
|
||||||
--x;
|
|
||||||
|
|
||||||
switch (*p) {
|
|
||||||
case 'A'...'Z':
|
|
||||||
case 'a'...'z':
|
|
||||||
++p;
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
++p;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
a1, a2 = 4, a3
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum crazyTAG {
|
|
||||||
x1, x2, x3 = 8, x4, x5
|
|
||||||
} myEnum, *pMyEnum;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
x1, x2, x3 = 8, x4, x5
|
|
||||||
} myEnum, *pMyEnum;
|
|
||||||
|
|
||||||
// Test multi-line macro:
|
|
||||||
|
|
||||||
#define MUILTILINE "abc" \
|
|
||||||
"xyz" \
|
|
||||||
"def"
|
|
||||||
|
|
||||||
#define MULTILINE(x, y) do { \
|
|
||||||
++y; ++x; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# dynlib iupdll
|
|
||||||
# cdecl
|
|
||||||
# mangle "'GTK_'{.*}" "TGtk$1"
|
|
||||||
# mangle "'PGTK_'{.*}" "PGtk$1"
|
|
||||||
# if defined(windows)
|
|
||||||
# define iupdll "iup.dll"
|
|
||||||
# elif defined(macosx)
|
|
||||||
# define iupdll "libiup.dynlib"
|
|
||||||
# else
|
|
||||||
# define iupdll "libiup.so"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct stupidTAG {
|
|
||||||
mytype a, b;
|
|
||||||
} GTK_MyStruct, *PGTK_MyStruct;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
mytype a, b;
|
|
||||||
} GTK_MyStruct, *PGTK_MyStruct;
|
|
||||||
|
|
||||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define OUT(x) printf("%s\n", x)
|
|
||||||
#else
|
|
||||||
# define OUT(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# def EXTERN(x) static x
|
|
||||||
# def TWO_ARGS(x, y) x* y
|
|
||||||
#endif
|
|
||||||
// parses now!
|
|
||||||
EXTERN(int) f(void);
|
|
||||||
EXTERN(int) g(void);
|
|
||||||
|
|
||||||
|
|
||||||
#def EXPORT
|
|
||||||
// does parse now!
|
|
||||||
EXPORT int f(void);
|
|
||||||
EXPORT int g(void);
|
|
||||||
|
|
||||||
static TWO_ARGS(int, x) = TWO_ARGS(56, 45);
|
|
||||||
|
|
||||||
|
|
||||||
# define abc 34
|
|
||||||
# define xyz 42
|
|
||||||
|
|
||||||
# define wuseldusel "my string\nconstant"
|
|
||||||
|
|
||||||
#undef ignoreThis
|
|
||||||
|
|
||||||
char* x;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char x, y, *z;
|
|
||||||
} point;
|
|
||||||
|
|
||||||
char* __stdcall printf(char* frmt, const char* const** ptrToStrArray,
|
|
||||||
const int* const dummy, ...);
|
|
||||||
|
|
||||||
inline char* myinlineProc(char* frmt, const char* const* strArray,
|
|
||||||
const int* const dummy, ...);
|
|
||||||
|
|
||||||
// Test void parameter list:
|
|
||||||
void myVoidProc(void);
|
|
||||||
|
|
||||||
void emptyReturn(void) { return; }
|
|
||||||
|
|
||||||
// POSIX stuff:
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
#prefix posix_
|
|
||||||
int c2nimBranch;
|
|
||||||
#elif defined(MACOSX)
|
|
||||||
int* x, y, z;
|
|
||||||
#else
|
|
||||||
int dummy;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef C2NIM
|
|
||||||
int dontTranslateThis;
|
|
||||||
#elif defined(Windows)
|
|
||||||
int WindowsTrue = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int posix_spawn(pid_t *restrict, const char *restrict,
|
|
||||||
const posix_spawn_file_actions_t *,
|
|
||||||
const posix_spawnattr_t *restrict, char *const [restrict],
|
|
||||||
char *const [restrict]);
|
|
||||||
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *,
|
|
||||||
int);
|
|
||||||
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *,
|
|
||||||
int, int);
|
|
||||||
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict,
|
|
||||||
int, const char *restrict, int, mode_t);
|
|
||||||
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *);
|
|
||||||
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *);
|
|
||||||
int posix_spawnattr_destroy(posix_spawnattr_t *);
|
|
||||||
int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict,
|
|
||||||
sigset_t *restrict);
|
|
||||||
int posix_spawnattr_getflags(const posix_spawnattr_t *restrict,
|
|
||||||
short *restrict);
|
|
||||||
int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict,
|
|
||||||
pid_t *restrict);
|
|
||||||
int posix_spawnattr_getschedparam(const posix_spawnattr_t *restrict,
|
|
||||||
struct sched_param *restrict);
|
|
||||||
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *restrict,
|
|
||||||
int *restrict);
|
|
||||||
int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict,
|
|
||||||
sigset_t *restrict);
|
|
||||||
int posix_spawnattr_init(posix_spawnattr_t *);
|
|
||||||
int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict,
|
|
||||||
const sigset_t *restrict);
|
|
||||||
int posix_spawnattr_setflags(posix_spawnattr_t *, short);
|
|
||||||
int posix_spawnattr_setpgroup(posix_spawnattr_t *, pid_t);
|
|
||||||
|
|
||||||
|
|
||||||
int posix_spawnattr_setschedparam(posix_spawnattr_t *restrict,
|
|
||||||
const struct sched_param *restrict);
|
|
||||||
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *, int);
|
|
||||||
int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict,
|
|
||||||
const sigset_t *restrict);
|
|
||||||
int posix_spawnp(pid_t *restrict, const char *restrict,
|
|
||||||
const posix_spawn_file_actions_t *,
|
|
||||||
const posix_spawnattr_t *restrict,
|
|
||||||
char *const [restrict], char *const [restrict]);
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
float R, G, B;
|
|
||||||
}
|
|
||||||
RGBType;
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
float H, W, B;
|
|
||||||
}
|
|
||||||
HWBType;
|
|
||||||
|
|
||||||
static HWBType *
|
|
||||||
RGB_to_HWB (RGBType RGB, HWBType * HWB)
|
|
||||||
{
|
|
||||||
HWBType* myArray[20];
|
|
||||||
/*
|
|
||||||
* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
|
|
||||||
* returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
|
|
||||||
*/
|
|
||||||
|
|
||||||
float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
w = MIN3 (R, G, B);
|
|
||||||
v = MAX3 (R, G, B);
|
|
||||||
b &= 1 - v;
|
|
||||||
if (v == w)
|
|
||||||
RETURN_HWB (HWB_UNDEFINED, w, b);
|
|
||||||
f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
|
|
||||||
i = (R == w) ? 3 : ((G == w) ? 5 : 1);
|
|
||||||
RETURN_HWB (i - f / (v - w), w, b);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
|
|
||||||
{
|
|
||||||
double m; // gradient of line
|
|
||||||
if (*x0 < mindim)
|
|
||||||
{ // start of line is left of window
|
|
||||||
if (*x1 < mindim) // as is the end, so the line never cuts the window
|
|
||||||
return 0;
|
|
||||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
|
||||||
// adjust x0 to be on the left boundary (ie to be zero), and y0 to match
|
|
||||||
*y0 -= m * (*x0 - mindim);
|
|
||||||
*x0 = mindim;
|
|
||||||
// now, perhaps, adjust the far end of the line as well
|
|
||||||
if (*x1 > maxdim)
|
|
||||||
{
|
|
||||||
*y1 += m * (maxdim - *x1);
|
|
||||||
*x1 = maxdim;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (*x0 > maxdim)
|
|
||||||
{ // start of line is right of window - complement of above
|
|
||||||
if (*x1 > maxdim) // as is the end, so the line misses the window
|
|
||||||
return 0;
|
|
||||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
|
||||||
*y0 += m * (maxdim - *x0); // adjust so point is on the right
|
|
||||||
// boundary
|
|
||||||
*x0 = maxdim;
|
|
||||||
// now, perhaps, adjust the end of the line
|
|
||||||
if (*x1 < mindim)
|
|
||||||
{
|
|
||||||
*y1 -= m * (*x1 - mindim);
|
|
||||||
*x1 = mindim;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// the final case - the start of the line is inside the window
|
|
||||||
if (*x1 > maxdim)
|
|
||||||
{ // other end is outside to the right
|
|
||||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
|
||||||
*y1 += m * (maxdim - *x1);
|
|
||||||
*x1 = maxdim;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (*x1 < mindim)
|
|
||||||
{ // other end is outside to the left
|
|
||||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of line
|
|
||||||
*y1 -= m * (*x1 - mindim);
|
|
||||||
*x1 = mindim;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// only get here if both points are inside the window
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end of line clipping code
|
|
||||||
|
|
||||||
static void
|
|
||||||
gdImageBrushApply (gdImagePtr im, int x, int y)
|
|
||||||
{
|
|
||||||
int lx, ly;
|
|
||||||
int hy;
|
|
||||||
int hx;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
int srcx, srcy;
|
|
||||||
if (!im->brush)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hy = gdImageSY (im->brush) / 2;
|
|
||||||
y1 = y - hy;
|
|
||||||
y2 = y1 + gdImageSY (im->brush);
|
|
||||||
hx = gdImageSX (im->brush) / 2;
|
|
||||||
x1 = x - hx;
|
|
||||||
x2 = x1 + gdImageSX (im->brush);
|
|
||||||
srcy = 0;
|
|
||||||
if (im->trueColor)
|
|
||||||
{
|
|
||||||
if (im->brush->trueColor)
|
|
||||||
{
|
|
||||||
for (ly = y1; (ly < y2); ly++)
|
|
||||||
{
|
|
||||||
srcx = 0;
|
|
||||||
for (lx = x1; (lx < x2); lx++)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
|
|
||||||
// 2.0.9, Thomas Winzig: apply simple full transparency
|
|
||||||
if (p != gdImageGetTransparent (im->brush))
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, lx, ly, p);
|
|
||||||
}
|
|
||||||
srcx++;
|
|
||||||
}
|
|
||||||
srcy++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
|
|
||||||
// for pointing out the issue)
|
|
||||||
for (ly = y1; (ly < y2); ly++)
|
|
||||||
{
|
|
||||||
srcx = 0;
|
|
||||||
for (lx = x1; (lx < x2); lx++)
|
|
||||||
{
|
|
||||||
int p, tc;
|
|
||||||
p = gdImageGetPixel (im->brush, srcx, srcy);
|
|
||||||
tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
|
|
||||||
// 2.0.9, Thomas Winzig: apply simple full transparency
|
|
||||||
if (p != gdImageGetTransparent (im->brush))
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, lx, ly, tc);
|
|
||||||
}
|
|
||||||
srcx++;
|
|
||||||
}
|
|
||||||
srcy++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (ly = y1; (ly < y2); ly++)
|
|
||||||
{
|
|
||||||
srcx = 0;
|
|
||||||
for (lx = x1; (lx < x2); lx++)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
p = gdImageGetPixel (im->brush, srcx, srcy);
|
|
||||||
// Allow for non-square brushes!
|
|
||||||
if (p != gdImageGetTransparent (im->brush))
|
|
||||||
{
|
|
||||||
// Truecolor brush. Very slow
|
|
||||||
// on a palette destination.
|
|
||||||
if (im->brush->trueColor)
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, lx, ly,
|
|
||||||
gdImageColorResolveAlpha(im,
|
|
||||||
gdTrueColorGetRed(p),
|
|
||||||
gdTrueColorGetGreen(p),
|
|
||||||
gdTrueColorGetBlue(p),
|
|
||||||
gdTrueColorGetAlpha(p)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
srcx++;
|
|
||||||
}
|
|
||||||
srcy++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
switch (color)
|
|
||||||
{
|
|
||||||
case gdStyled:
|
|
||||||
if (!im->style)
|
|
||||||
{
|
|
||||||
// Refuse to draw if no style is set.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p = im->style[im->stylePos++];
|
|
||||||
}
|
|
||||||
if (p != (gdTransparent))
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, x, y, p);
|
|
||||||
}
|
|
||||||
im->stylePos = im->stylePos % im->styleLength;
|
|
||||||
break;
|
|
||||||
case gdStyledBrushed:
|
|
||||||
if (!im->style)
|
|
||||||
{
|
|
||||||
// Refuse to draw if no style is set.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p = im->style[im->stylePos++];
|
|
||||||
if ((p != gdTransparent) && (p != 0))
|
|
||||||
{
|
|
||||||
gdImageSetPixel (im, x, y, gdBrushed);
|
|
||||||
}
|
|
||||||
im->stylePos = im->stylePos % im->styleLength;
|
|
||||||
break;
|
|
||||||
case gdBrushed:
|
|
||||||
gdImageBrushApply (im, x, y);
|
|
||||||
break;
|
|
||||||
case gdTiled:
|
|
||||||
gdImageTileApply (im, x, y);
|
|
||||||
break;
|
|
||||||
case gdAntiAliased:
|
|
||||||
// This shouldn't happen (2.0.26) because we just call
|
|
||||||
// gdImageAALine now, but do something sane.
|
|
||||||
gdImageSetPixel(im, x, y, im->AA_color);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (gdImageBoundsSafeMacro (im, x, y))
|
|
||||||
{
|
|
||||||
if (im->trueColor)
|
|
||||||
{
|
|
||||||
if (im->alphaBlendingFlag)
|
|
||||||
{
|
|
||||||
im->tpixels[y][x] = gdAlphaBlend (im->tpixels[y][x], color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
im->tpixels[y][x] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
im->pixels[y][x] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#ifdef C2NIM
|
|
||||||
# header "iup.h"
|
|
||||||
# cdecl
|
|
||||||
# mangle "'GTK_'{.*}" "TGtk$1"
|
|
||||||
# mangle "'PGTK_'{.*}" "PGtk$1"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct stupidTAG {
|
|
||||||
mytype a, b;
|
|
||||||
} GTK_MyStruct, *PGTK_MyStruct;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
mytype a, b;
|
|
||||||
} GTK_MyStruct, *PGTK_MyStruct;
|
|
||||||
|
|
||||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#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';
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
struct foo {
|
|
||||||
int x,y,z;
|
|
||||||
};
|
|
||||||
|
|
@ -29,7 +29,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||||
# Great, we can use 'd':
|
# Great, we can use 'd':
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
|
||||||
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
||||||
# reset before pass as 'result' var:
|
# reset before pass as 'result' var:
|
||||||
resetLoc(p, d)
|
resetLoc(p, d)
|
||||||
|
|
@ -38,7 +38,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
else:
|
else:
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
getTemp(p, typ.sons[0], tmp)
|
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||||
app(pl, addrLoc(tmp))
|
app(pl, addrLoc(tmp))
|
||||||
app(pl, ~");$n")
|
app(pl, ~");$n")
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
|
|
@ -195,7 +195,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||||
# Great, we can use 'd':
|
# Great, we can use 'd':
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if d.k == locNone:
|
||||||
|
getTemp(p, typ.sons[0], d, needsInit=true)
|
||||||
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
||||||
# reset before pass as 'result' var:
|
# reset before pass as 'result' var:
|
||||||
resetLoc(p, d)
|
resetLoc(p, d)
|
||||||
|
|
@ -203,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
genCallPattern()
|
genCallPattern()
|
||||||
else:
|
else:
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
getTemp(p, typ.sons[0], tmp)
|
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||||
app(pl, addrLoc(tmp))
|
app(pl, addrLoc(tmp))
|
||||||
genCallPattern()
|
genCallPattern()
|
||||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||||
|
|
@ -278,14 +279,14 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||||
if d.k in {locTemp, locNone}:
|
if d.k in {locTemp, locNone}:
|
||||||
# We already got a temp. Great, special case it:
|
# We already got a temp. Great, special case it:
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
|
||||||
app(pl, ~"Result: ")
|
app(pl, ~"Result: ")
|
||||||
app(pl, addrLoc(d))
|
app(pl, addrLoc(d))
|
||||||
app(pl, ~"];$n")
|
app(pl, ~"];$n")
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
else:
|
else:
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
getTemp(p, typ.sons[0], tmp)
|
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||||
app(pl, addrLoc(tmp))
|
app(pl, addrLoc(tmp))
|
||||||
app(pl, ~"];$n")
|
app(pl, ~"];$n")
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,32 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
else: internalError("genAssignment: " & $ty.kind)
|
else: internalError("genAssignment: " & $ty.kind)
|
||||||
|
|
||||||
|
proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||||
|
var ty = skipTypes(dest.t, abstractVarRange)
|
||||||
|
case ty.kind
|
||||||
|
of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray, tyArrayConstr:
|
||||||
|
# XXX optimize this
|
||||||
|
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
|
||||||
|
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
|
||||||
|
of tySequence, tyString:
|
||||||
|
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
|
||||||
|
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
|
||||||
|
of tyOpenArray, tyVarargs:
|
||||||
|
linefmt(p, cpsStmts,
|
||||||
|
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n",
|
||||||
|
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
|
||||||
|
of tySet:
|
||||||
|
if mapType(ty) == ctArray:
|
||||||
|
useStringh(p.module)
|
||||||
|
linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
|
||||||
|
rdLoc(dest), rdLoc(src), toRope(getSize(dest.t)))
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
|
of tyPointer, tyChar, tyBool, tyEnum, tyCString,
|
||||||
|
tyInt..tyUInt64, tyRange, tyVar:
|
||||||
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
|
else: internalError("genDeepCopy: " & $ty.kind)
|
||||||
|
|
||||||
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
|
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
|
||||||
if d.k == locNone: getTemp(p, typ, d)
|
if d.k == locNone: getTemp(p, typ, d)
|
||||||
|
|
||||||
|
|
@ -1191,7 +1217,6 @@ proc genOf(p: BProc, n: PNode, d: var TLoc) =
|
||||||
genOf(p, n.sons[1], n.sons[2].typ, d)
|
genOf(p, n.sons[1], n.sons[2].typ, d)
|
||||||
|
|
||||||
proc genRepr(p: BProc, e: 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
|
var a: TLoc
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
||||||
|
|
@ -1260,6 +1285,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
|
if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
|
||||||
else: unaryExpr(p, e, d, "$1Len0")
|
else: unaryExpr(p, e, d, "$1Len0")
|
||||||
of tyCString:
|
of tyCString:
|
||||||
|
useStringh(p.module)
|
||||||
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
||||||
else: unaryExpr(p, e, d, "strlen($1)")
|
else: unaryExpr(p, e, d, "strlen($1)")
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
|
|
@ -1578,25 +1604,25 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mGetTypeInfo: genGetTypeInfo(p, e, d)
|
of mGetTypeInfo: genGetTypeInfo(p, e, d)
|
||||||
of mSwap: genSwap(p, e, d)
|
of mSwap: genSwap(p, e, d)
|
||||||
of mUnaryLt:
|
of mUnaryLt:
|
||||||
if not (optOverflowCheck in p.options): unaryExpr(p, e, d, "$1 - 1")
|
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||||
of mPred:
|
of mPred:
|
||||||
# XXX: range checking?
|
# XXX: range checking?
|
||||||
if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 - $2")
|
if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 - $2)")
|
||||||
else: binaryExpr(p, e, d, "#subInt($1, $2)")
|
else: binaryExpr(p, e, d, "#subInt($1, $2)")
|
||||||
of mSucc:
|
of mSucc:
|
||||||
# XXX: range checking?
|
# XXX: range checking?
|
||||||
if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 + $2")
|
if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 + $2)")
|
||||||
else: binaryExpr(p, e, d, "#addInt($1, $2)")
|
else: binaryExpr(p, e, d, "#addInt($1, $2)")
|
||||||
of mInc:
|
of mInc:
|
||||||
if not (optOverflowCheck in p.options):
|
if optOverflowCheck notin p.options:
|
||||||
binaryStmt(p, e, d, "$1 += $2;$n")
|
binaryStmt(p, e, d, "$1 += $2;$n")
|
||||||
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
||||||
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
|
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
|
||||||
else:
|
else:
|
||||||
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
|
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
|
||||||
of ast.mDec:
|
of ast.mDec:
|
||||||
if not (optOverflowCheck in p.options):
|
if optOverflowCheck notin p.options:
|
||||||
binaryStmt(p, e, d, "$1 -= $2;$n")
|
binaryStmt(p, e, d, "$1 -= $2;$n")
|
||||||
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
||||||
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
|
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
|
||||||
|
|
@ -1640,7 +1666,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
|
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
|
||||||
mInSet:
|
mInSet:
|
||||||
genSetOp(p, e, d, op)
|
genSetOp(p, e, d, op)
|
||||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit:
|
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit,
|
||||||
|
mParseBiggestFloat:
|
||||||
var opr = e.sons[0].sym
|
var opr = e.sons[0].sym
|
||||||
if lfNoDecl notin opr.loc.flags:
|
if lfNoDecl notin opr.loc.flags:
|
||||||
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
||||||
|
|
@ -1658,6 +1685,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mParallel:
|
of mParallel:
|
||||||
let n = semparallel.liftParallel(p.module.module, e)
|
let n = semparallel.liftParallel(p.module.module, e)
|
||||||
expr(p, n, d)
|
expr(p, n, d)
|
||||||
|
of mDeepCopy:
|
||||||
|
var a, b: TLoc
|
||||||
|
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
|
||||||
|
initLocExpr(p, x, a)
|
||||||
|
initLocExpr(p, e.sons[2], b)
|
||||||
|
genDeepCopy(p, a, b)
|
||||||
else: internalError(e.info, "genMagicExpr: " & $op)
|
else: internalError(e.info, "genMagicExpr: " & $op)
|
||||||
|
|
||||||
proc genConstExpr(p: BProc, n: PNode): PRope
|
proc genConstExpr(p: BProc, n: PNode): PRope
|
||||||
|
|
@ -1877,7 +1910,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
of skVar, skForVar, skResult, skLet:
|
of skVar, skForVar, skResult, skLet:
|
||||||
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
internalError(n.info, "expr: var not init " & sym.name.s)
|
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||||
|
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
||||||
if sfThread in sym.flags:
|
if sfThread in sym.flags:
|
||||||
accessThreadLocalVar(p, sym)
|
accessThreadLocalVar(p, sym)
|
||||||
if emulatedThreadVars():
|
if emulatedThreadVars():
|
||||||
|
|
@ -1888,11 +1922,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
of skTemp:
|
of skTemp:
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
internalError(n.info, "expr: temp not init " & sym.name.s)
|
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||||
|
#echo renderTree(p.prc.ast, {renderIds})
|
||||||
|
internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
of skParam:
|
of skParam:
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
internalError(n.info, "expr: param not init " & sym.name.s)
|
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||||
|
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||||
putLocIntoDest(p, d, sym.loc)
|
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:
|
of nkNilLit:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -24,10 +24,29 @@ proc registerGcRoot(p: BProc, v: PSym) =
|
||||||
linefmt(p.module.initProc, cpsStmts,
|
linefmt(p.module.initProc, cpsStmts,
|
||||||
"#nimRegisterGlobalMarker($1);$n", prc)
|
"#nimRegisterGlobalMarker($1);$n", prc)
|
||||||
|
|
||||||
|
proc isAssignedImmediately(n: PNode): bool {.inline.} =
|
||||||
|
if n.kind == nkEmpty: return false
|
||||||
|
if isInvalidReturnType(n.typ):
|
||||||
|
# var v = f()
|
||||||
|
# is transformed into: var v; f(addr v)
|
||||||
|
# where 'f' **does not** initialize the result!
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
proc genVarTuple(p: BProc, n: PNode) =
|
proc genVarTuple(p: BProc, n: PNode) =
|
||||||
var tup, field: TLoc
|
var tup, field: TLoc
|
||||||
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
||||||
var L = sonsLen(n)
|
var L = sonsLen(n)
|
||||||
|
|
||||||
|
# if we have a something that's been captured, use the lowering instead:
|
||||||
|
var useLowering = false
|
||||||
|
for i in countup(0, L-3):
|
||||||
|
if n[i].kind != nkSym:
|
||||||
|
useLowering = true; break
|
||||||
|
if useLowering:
|
||||||
|
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||||
|
return
|
||||||
|
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
initLocExpr(p, n.sons[L-1], tup)
|
initLocExpr(p, n.sons[L-1], tup)
|
||||||
var t = tup.t
|
var t = tup.t
|
||||||
|
|
@ -40,7 +59,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
registerGcRoot(p, v)
|
registerGcRoot(p, v)
|
||||||
else:
|
else:
|
||||||
assignLocalVar(p, v)
|
assignLocalVar(p, v)
|
||||||
initLocalVar(p, v, immediateAsgn=true)
|
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
|
||||||
initLoc(field, locExpr, t.sons[i], tup.s)
|
initLoc(field, locExpr, t.sons[i], tup.s)
|
||||||
if t.kind == tyTuple:
|
if t.kind == tyTuple:
|
||||||
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
||||||
|
|
@ -146,12 +165,16 @@ proc genBreakState(p: BProc, n: PNode) =
|
||||||
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
|
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
|
||||||
|
|
||||||
proc genVarPrototypeAux(m: BModule, sym: PSym)
|
proc genVarPrototypeAux(m: BModule, sym: PSym)
|
||||||
|
|
||||||
proc genSingleVar(p: BProc, a: PNode) =
|
proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
if sfCompileTime in v.flags: return
|
if sfCompileTime in v.flags: return
|
||||||
var targetProc = p
|
var targetProc = p
|
||||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
|
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
|
||||||
|
a.sons[2].kind == nkEmpty and
|
||||||
|
v.loc.flags * {lfHeader, lfNoDecl} != {}:
|
||||||
|
return
|
||||||
if sfPure in v.flags:
|
if sfPure in v.flags:
|
||||||
# v.owner.kind != skModule:
|
# v.owner.kind != skModule:
|
||||||
targetProc = p.module.preInitProc
|
targetProc = p.module.preInitProc
|
||||||
|
|
@ -170,9 +193,9 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
registerGcRoot(p, v)
|
registerGcRoot(p, v)
|
||||||
else:
|
else:
|
||||||
assignLocalVar(p, v)
|
assignLocalVar(p, v)
|
||||||
initLocalVar(p, v, immediateAsgn)
|
initLocalVar(p, v, isAssignedImmediately(a.sons[2]))
|
||||||
|
|
||||||
if immediateAsgn:
|
if a.sons[2].kind != nkEmpty:
|
||||||
genLineDir(targetProc, a)
|
genLineDir(targetProc, a)
|
||||||
loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
|
loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
|
||||||
|
|
||||||
|
|
@ -809,6 +832,13 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
discard cgsym(p.module, "E_Base")
|
discard cgsym(p.module, "E_Base")
|
||||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||||
|
if isDefined("nimStdSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||||
|
elif isDefined("nimSigSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
|
||||||
|
elif isDefined("nimRawSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
|
||||||
|
else:
|
||||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||||
var length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ type
|
||||||
|
|
||||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
|
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
|
||||||
proc genCaseRange(p: BProc, branch: PNode)
|
proc genCaseRange(p: BProc, branch: PNode)
|
||||||
proc getTemp(p: BProc, t: PType, result: var TLoc)
|
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
|
||||||
|
|
||||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ proc mapSetType(typ: PType): TCTypeKind =
|
||||||
else: result = ctArray
|
else: result = ctArray
|
||||||
|
|
||||||
proc mapType(typ: PType): TCTypeKind =
|
proc mapType(typ: PType): TCTypeKind =
|
||||||
|
## Maps a nimrod type to a C type
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tyNone, tyStmt: result = ctVoid
|
of tyNone, tyStmt: result = ctVoid
|
||||||
of tyBool: result = ctBool
|
of tyBool: result = ctBool
|
||||||
|
|
@ -453,7 +454,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
appf(result, " {$n", [name])
|
appf(result, " {$n", [name])
|
||||||
|
|
||||||
var desc = getRecordFields(m, typ, check)
|
var desc = getRecordFields(m, typ, check)
|
||||||
if (desc == nil) and not hasField:
|
if desc == nil and not hasField:
|
||||||
appf(result, "char dummy;$n", [])
|
appf(result, "char dummy;$n", [])
|
||||||
else:
|
else:
|
||||||
app(result, desc)
|
app(result, desc)
|
||||||
|
|
@ -722,7 +723,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||||
if objtype.sym == nil:
|
if objtype.sym == nil:
|
||||||
internalError(d.info, "anonymous obj with discriminator")
|
internalError(d.info, "anonymous obj with discriminator")
|
||||||
result = ropef("NimDT_$1_$2", [
|
result = ropef("NimDT_$1_$2", [
|
||||||
toRope(objtype.sym.name.s.mangle), toRope(d.name.s.mangle)])
|
toRope(objtype.id), toRope(d.name.s.mangle)])
|
||||||
|
|
||||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
||||||
discard cgsym(m, "TNimNode")
|
discard cgsym(m, "TNimNode")
|
||||||
|
|
@ -895,11 +896,20 @@ type
|
||||||
|
|
||||||
include ccgtrav
|
include ccgtrav
|
||||||
|
|
||||||
|
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||||
|
genProc(m, s)
|
||||||
|
appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n",
|
||||||
|
[result, s.loc.r])
|
||||||
|
|
||||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||||
|
let origType = t
|
||||||
var t = getUniqueType(t)
|
var t = getUniqueType(t)
|
||||||
result = ropef("NTI$1", [toRope(t.id)])
|
result = ropef("NTI$1", [toRope(t.id)])
|
||||||
if containsOrIncl(m.typeInfoMarker, t.id):
|
if containsOrIncl(m.typeInfoMarker, t.id):
|
||||||
return con("(&".toRope, result, ")".toRope)
|
return con("(&".toRope, result, ")".toRope)
|
||||||
|
|
||||||
|
# getUniqueType doesn't skip tyDistinct when that has an overriden operation:
|
||||||
|
while t.kind == tyDistinct: t = t.lastSon
|
||||||
let owner = t.skipTypes(typedescPtrs).owner.getModule
|
let owner = t.skipTypes(typedescPtrs).owner.getModule
|
||||||
if owner != m.module:
|
if owner != m.module:
|
||||||
# make sure the type info is created in the owner module
|
# make sure the type info is created in the owner module
|
||||||
|
|
@ -936,6 +946,10 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||||
# results are not deterministic!
|
# results are not deterministic!
|
||||||
genTupleInfo(m, t, result)
|
genTupleInfo(m, t, result)
|
||||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||||
|
if t.deepCopy != nil:
|
||||||
|
genDeepCopyProc(m, t.deepCopy, result)
|
||||||
|
elif origType.deepCopy != nil:
|
||||||
|
genDeepCopyProc(m, origType.deepCopy, result)
|
||||||
result = con("(&".toRope, result, ")".toRope)
|
result = con("(&".toRope, result, ")".toRope)
|
||||||
|
|
||||||
proc genTypeSection(m: BModule, n: PNode) =
|
proc genTypeSection(m: BModule, n: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,15 @@ proc getUniqueType*(key: PType): PType =
|
||||||
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
||||||
tyFromExpr, tyFieldAccessor:
|
tyFromExpr, tyFieldAccessor:
|
||||||
internalError("GetUniqueType")
|
internalError("GetUniqueType")
|
||||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
|
of tyDistinct:
|
||||||
tyConst, tyIter, tyStatic:
|
if key.deepCopy != nil: result = key
|
||||||
|
else: result = getUniqueType(lastSon(key))
|
||||||
|
of tyGenericInst, tyOrdinal, tyMutable, tyConst, tyIter, tyStatic:
|
||||||
result = getUniqueType(lastSon(key))
|
result = getUniqueType(lastSon(key))
|
||||||
|
#let obj = lastSon(key)
|
||||||
|
#if obj.sym != nil and obj.sym.name.s == "TOption":
|
||||||
|
# echo "for ", typeToString(key), " I returned "
|
||||||
|
# debug result
|
||||||
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
||||||
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
||||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||||
options, intsets,
|
options, intsets,
|
||||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
|
||||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
||||||
semparallel
|
semparallel
|
||||||
|
|
||||||
|
|
@ -295,6 +295,7 @@ proc postStmtActions(p: BProc) {.inline.} =
|
||||||
|
|
||||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||||
proc emulatedThreadVars(): bool {.inline.}
|
proc emulatedThreadVars(): bool {.inline.}
|
||||||
|
proc genProc(m: BModule, prc: PSym)
|
||||||
|
|
||||||
include "ccgtypes.nim"
|
include "ccgtypes.nim"
|
||||||
|
|
||||||
|
|
@ -398,7 +399,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
if not immediateAsgn:
|
if not immediateAsgn:
|
||||||
constructLoc(p, v.loc)
|
constructLoc(p, v.loc)
|
||||||
|
|
||||||
proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if gCmd == cmdCompileToLLVM:
|
if gCmd == cmdCompileToLLVM:
|
||||||
result.r = con("%LOC", toRope(p.labels))
|
result.r = con("%LOC", toRope(p.labels))
|
||||||
|
|
@ -410,7 +411,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
||||||
result.t = getUniqueType(t)
|
result.t = getUniqueType(t)
|
||||||
result.s = OnStack
|
result.s = OnStack
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
constructLoc(p, result, isTemp=true)
|
constructLoc(p, result, not needsInit)
|
||||||
|
|
||||||
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -574,7 +575,6 @@ proc fixLabel(p: BProc, labl: TLabel) =
|
||||||
|
|
||||||
proc genVarPrototype(m: BModule, sym: PSym)
|
proc genVarPrototype(m: BModule, sym: PSym)
|
||||||
proc requestConstImpl(p: BProc, sym: PSym)
|
proc requestConstImpl(p: BProc, sym: PSym)
|
||||||
proc genProc(m: BModule, prc: PSym)
|
|
||||||
proc genStmts(p: BProc, t: PNode)
|
proc genStmts(p: BProc, t: PNode)
|
||||||
proc expr(p: BProc, n: PNode, d: var TLoc)
|
proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||||
proc genProcPrototype(m: BModule, sym: PSym)
|
proc genProcPrototype(m: BModule, sym: PSym)
|
||||||
|
|
@ -949,13 +949,23 @@ proc genFilenames(m: BModule): PRope =
|
||||||
|
|
||||||
proc genMainProc(m: BModule) =
|
proc genMainProc(m: BModule) =
|
||||||
const
|
const
|
||||||
|
# The use of a volatile function pointer to call Pre/NimMainInner
|
||||||
|
# prevents inlining of the NimMainInner function and dependent
|
||||||
|
# functions, which might otherwise merge their stack frames.
|
||||||
PreMainBody =
|
PreMainBody =
|
||||||
"\tsystemDatInit();$N" &
|
"void PreMainInner() {$N" &
|
||||||
"\tsystemInit();$N" &
|
"\tsystemInit();$N" &
|
||||||
"$1" &
|
"$1" &
|
||||||
"$2" &
|
"$2" &
|
||||||
"$3" &
|
"$3" &
|
||||||
"$4"
|
"}$N$N" &
|
||||||
|
"void PreMain() {$N" &
|
||||||
|
"\tvoid (*volatile inner)();$N" &
|
||||||
|
"\tsystemDatInit();$N" &
|
||||||
|
"\tinner = PreMainInner;$N" &
|
||||||
|
"$4" &
|
||||||
|
"\t(*inner)();$N" &
|
||||||
|
"}$N$N"
|
||||||
|
|
||||||
MainProcs =
|
MainProcs =
|
||||||
"\tNimMain();$N"
|
"\tNimMain();$N"
|
||||||
|
|
@ -964,9 +974,15 @@ proc genMainProc(m: BModule) =
|
||||||
MainProcs & "\treturn nim_program_result;$N"
|
MainProcs & "\treturn nim_program_result;$N"
|
||||||
|
|
||||||
NimMainBody =
|
NimMainBody =
|
||||||
"N_CDECL(void, NimMain)(void) {$N" &
|
"N_CDECL(void, NimMainInner)(void) {$N" &
|
||||||
"\tPreMain();$N" &
|
|
||||||
"$1" &
|
"$1" &
|
||||||
|
"}$N$N" &
|
||||||
|
"N_CDECL(void, NimMain)(void) {$N" &
|
||||||
|
"\tvoid (*volatile inner)();$N" &
|
||||||
|
"\tPreMain();$N" &
|
||||||
|
"\tinner = NimMainInner;$N" &
|
||||||
|
"$2" &
|
||||||
|
"\t(*inner)();$N" &
|
||||||
"}$N$N"
|
"}$N$N"
|
||||||
|
|
||||||
PosixNimMain =
|
PosixNimMain =
|
||||||
|
|
@ -1034,14 +1050,15 @@ proc genMainProc(m: BModule) =
|
||||||
if optEndb in gOptions:
|
if optEndb in gOptions:
|
||||||
gBreakpoints.app(m.genFilenames)
|
gBreakpoints.app(m.genFilenames)
|
||||||
|
|
||||||
let initStackBottomCall = if emulatedThreadVars() or
|
let initStackBottomCall =
|
||||||
|
if emulatedThreadVars() or
|
||||||
platform.targetOS == osStandalone: "".toRope
|
platform.targetOS == osStandalone: "".toRope
|
||||||
else: ropecg(m, "\t#initStackBottom();$N")
|
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||||
inc(m.labels)
|
inc(m.labels)
|
||||||
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
|
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||||
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
|
mainDatInit, gBreakpoints, otherModsInit, initStackBottomCall])
|
||||||
|
|
||||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
|
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
|
||||||
if optNoMain notin gGlobalOptions:
|
if optNoMain notin gGlobalOptions:
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,9 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]))
|
CPU[platform.hostCPU].name]))
|
||||||
|
|
||||||
const gitHash = gorge("git log -n 1 --format=%H")
|
discard """const gitHash = gorge("git log -n 1 --format=%H")
|
||||||
if gitHash.strip.len == 40:
|
if gitHash.strip.len == 40:
|
||||||
msgWriteln("git hash: " & gitHash)
|
msgWriteln("git hash: " & gitHash)"""
|
||||||
|
|
||||||
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
||||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
||||||
|
|
@ -291,8 +291,12 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
of "excludepath":
|
of "excludepath":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
let path = processPath(arg)
|
let path = processPath(arg)
|
||||||
lists.excludeStr(options.searchPaths, path)
|
lists.excludePath(options.searchPaths, path)
|
||||||
lists.excludeStr(options.lazyPaths, path)
|
lists.excludePath(options.lazyPaths, path)
|
||||||
|
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
|
||||||
|
let strippedPath = path[0 .. (len(path) - 2)]
|
||||||
|
lists.excludePath(options.searchPaths, strippedPath)
|
||||||
|
lists.excludePath(options.lazyPaths, strippedPath)
|
||||||
of "nimcache":
|
of "nimcache":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
options.nimcacheDir = processPath(arg)
|
options.nimcacheDir = processPath(arg)
|
||||||
|
|
@ -311,6 +315,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
of "undef", "u":
|
of "undef", "u":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
undefSymbol(arg)
|
undefSymbol(arg)
|
||||||
|
of "symbol":
|
||||||
|
expectArg(switch, arg, pass, info)
|
||||||
|
declareSymbol(arg)
|
||||||
of "compile":
|
of "compile":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: processCompile(arg)
|
if pass in {passCmd2, passPP}: processCompile(arg)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -19,6 +19,9 @@ var gSymbols: PStringTable
|
||||||
proc defineSymbol*(symbol: string) =
|
proc defineSymbol*(symbol: string) =
|
||||||
gSymbols[symbol] = "true"
|
gSymbols[symbol] = "true"
|
||||||
|
|
||||||
|
proc declareSymbol*(symbol: string) =
|
||||||
|
gSymbols[symbol] = "unknown"
|
||||||
|
|
||||||
proc undefSymbol*(symbol: string) =
|
proc undefSymbol*(symbol: string) =
|
||||||
gSymbols[symbol] = "false"
|
gSymbols[symbol] = "false"
|
||||||
|
|
||||||
|
|
@ -27,6 +30,7 @@ proc isDefined*(symbol: string): bool =
|
||||||
result = gSymbols[symbol] == "true"
|
result = gSymbols[symbol] == "true"
|
||||||
|
|
||||||
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
||||||
|
proc isDeclared*(symbol: PIdent): bool = gSymbols.hasKey(symbol.s)
|
||||||
|
|
||||||
iterator definedSymbolNames*: string =
|
iterator definedSymbolNames*: string =
|
||||||
for key, val in pairs(gSymbols):
|
for key, val in pairs(gSymbols):
|
||||||
|
|
@ -37,6 +41,38 @@ proc countDefinedSymbols*(): int =
|
||||||
for key, val in pairs(gSymbols):
|
for key, val in pairs(gSymbols):
|
||||||
if val == "true": inc(result)
|
if val == "true": inc(result)
|
||||||
|
|
||||||
|
# For ease of bootstrapping, we keep there here and not in the global config
|
||||||
|
# file for now:
|
||||||
|
const
|
||||||
|
additionalSymbols = """
|
||||||
|
x86 itanium x8664
|
||||||
|
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS doslike hpux
|
||||||
|
mac
|
||||||
|
|
||||||
|
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
|
||||||
|
|
||||||
|
ecmascript js nimrodvm nimffi nimdoc cpp objc
|
||||||
|
gcc llvmgcc clang lcc bcc dmc wcc vcc tcc pcc ucc icl
|
||||||
|
boehmgc gcmarkandsweep gcgenerational nogc gcUseBitvectors
|
||||||
|
endb profiler
|
||||||
|
executable guiapp consoleapp library dll staticlib
|
||||||
|
|
||||||
|
quick
|
||||||
|
release debug
|
||||||
|
useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
|
||||||
|
nodejs kwin nimfix
|
||||||
|
|
||||||
|
usesysassert usegcassert tinyC useFFI
|
||||||
|
useStdoutAsStdmsg createNimRtl
|
||||||
|
booting fulldebug corruption nimsuperops noSignalHandler useGnuReadline
|
||||||
|
noCaas noDocGen noBusyWaiting nativeStackTrace useNodeIds selftest
|
||||||
|
reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
|
||||||
|
debugExecProcesses pcreDll useLipzipSrc
|
||||||
|
preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
|
||||||
|
|
||||||
|
nimStdSetjmp nimRawSetjmp nimSigSetjmp
|
||||||
|
""".split
|
||||||
|
|
||||||
proc initDefines*() =
|
proc initDefines*() =
|
||||||
gSymbols = newStringTable(modeStyleInsensitive)
|
gSymbols = newStringTable(modeStyleInsensitive)
|
||||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
defineSymbol("nimrod") # 'nimrod' is always defined
|
||||||
|
|
@ -50,8 +86,21 @@ proc initDefines*() =
|
||||||
defineSymbol("nimunion")
|
defineSymbol("nimunion")
|
||||||
defineSymbol("nimnewshared")
|
defineSymbol("nimnewshared")
|
||||||
defineSymbol("nimrequiresnimframe")
|
defineSymbol("nimrequiresnimframe")
|
||||||
|
defineSymbol("nimparsebiggestfloatmagic")
|
||||||
|
defineSymbol("nimalias")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
|
for c in low(CPU)..high(CPU):
|
||||||
|
declareSymbol("cpu" & $CPU[c].bit)
|
||||||
|
declareSymbol(normalize(EndianToStr[CPU[c].endian]))
|
||||||
|
declareSymbol(CPU[c].name)
|
||||||
|
for o in low(platform.OS)..high(platform.OS):
|
||||||
|
declareSymbol(platform.OS[o].name)
|
||||||
|
|
||||||
|
for a in additionalSymbols:
|
||||||
|
declareSymbol(a)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
case targetCPU
|
case targetCPU
|
||||||
of cpuI386: defineSymbol("x86")
|
of cpuI386: defineSymbol("x86")
|
||||||
of cpuIa64: defineSymbol("itanium")
|
of cpuIa64: defineSymbol("itanium")
|
||||||
|
|
@ -87,5 +136,10 @@ proc initDefines*() =
|
||||||
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
|
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
|
||||||
defineSymbol(CPU[targetCPU].name)
|
defineSymbol(CPU[targetCPU].name)
|
||||||
defineSymbol(platform.OS[targetOS].name)
|
defineSymbol(platform.OS[targetOS].name)
|
||||||
|
declareSymbol("emulatedthreadvars")
|
||||||
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
||||||
defineSymbol("emulatedthreadvars")
|
defineSymbol("emulatedthreadvars")
|
||||||
|
case targetOS
|
||||||
|
of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx:
|
||||||
|
defineSymbol("nimRawSetjmp")
|
||||||
|
else: discard
|
||||||
|
|
|
||||||
|
|
@ -758,7 +758,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
|
||||||
result = impliesLe(fact, a, b)
|
result = impliesLe(fact, a, b)
|
||||||
if result != impUnknown: return result
|
if result != impUnknown: return result
|
||||||
if sameTree(y, a):
|
if sameTree(y, a):
|
||||||
result = ple(m, x, b)
|
result = ple(m, b, x)
|
||||||
if result != impUnknown: return result
|
if result != impUnknown: return result
|
||||||
|
|
||||||
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
|
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,25 @@
|
||||||
# This is the JavaScript code generator.
|
# This is the JavaScript code generator.
|
||||||
# Soon also a Luajit code generator. ;-)
|
# Soon also a Luajit code generator. ;-)
|
||||||
|
|
||||||
|
discard """
|
||||||
|
The JS code generator contains only 2 tricks:
|
||||||
|
|
||||||
|
Trick 1
|
||||||
|
-------
|
||||||
|
Some locations (for example 'var int') require "fat pointers" (``etyBaseIndex``)
|
||||||
|
which are pairs (array, index). The derefence operation is then 'array[index]'.
|
||||||
|
Check ``mapType`` for the details.
|
||||||
|
|
||||||
|
Trick 2
|
||||||
|
-------
|
||||||
|
It is preferable to generate '||' and '&&' if possible since that is more
|
||||||
|
idiomatic and hence should be friendlier for the JS JIT implementation. However
|
||||||
|
code like ``foo and (let bar = baz())`` cannot be translated this way. Instead
|
||||||
|
the expressions need to be transformed into statements. ``isSimpleExpr``
|
||||||
|
implements the required case distinction.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||||
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
||||||
|
|
@ -833,8 +852,8 @@ proc genSwap(p: PProc, n: PNode) =
|
||||||
"local $1 = $2; $2 = $3; $3 = $1;$n", [
|
"local $1 = $2; $2 = $3; $3 = $1;$n", [
|
||||||
tmp, a.address, b.address])
|
tmp, a.address, b.address])
|
||||||
tmp = tmp2
|
tmp = tmp2
|
||||||
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1" |
|
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||||
"local $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
|
"local $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
||||||
|
|
||||||
proc getFieldPosition(f: PNode): int =
|
proc getFieldPosition(f: PNode): int =
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -881,14 +900,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
a, b: TCompRes
|
a, b: TCompRes
|
||||||
first: BiggestInt
|
first: BiggestInt
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
gen(p, n.sons[0], a)
|
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
|
||||||
gen(p, n.sons[1], b)
|
gen(p, m.sons[0], a)
|
||||||
|
gen(p, m.sons[1], b)
|
||||||
internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
|
internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
|
||||||
r.address = a.res
|
r.address = a.res
|
||||||
var typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
var typ = skipTypes(m.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
|
else: first = 0
|
||||||
if optBoundsCheck in p.options and not isConstExpr(n.sons[1]):
|
if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
|
||||||
useMagic(p, "chckIndx")
|
useMagic(p, "chckIndx")
|
||||||
r.res = ropef("chckIndx($1, $2, $3.length)-$2",
|
r.res = ropef("chckIndx($1, $2, $3.length)-$2",
|
||||||
[b.res, toRope(first), a.res])
|
[b.res, toRope(first), a.res])
|
||||||
|
|
@ -1321,7 +1341,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||||
unaryExpr(p, n, r, "", "$1.length")
|
unaryExpr(p, n, r, "", "$1.length")
|
||||||
of mHigh:
|
of mHigh:
|
||||||
if skipTypes(n.sons[0].typ, abstractVar).kind == tyString:
|
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
|
||||||
unaryExpr(p, n, r, "", "($1.length-2)")
|
unaryExpr(p, n, r, "", "($1.length-2)")
|
||||||
else:
|
else:
|
||||||
unaryExpr(p, n, r, "", "($1.length-1)")
|
unaryExpr(p, n, r, "", "($1.length-1)")
|
||||||
|
|
@ -1351,7 +1371,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mEcho: genEcho(p, n, r)
|
of mEcho: genEcho(p, n, r)
|
||||||
of mSlurp, mStaticExec:
|
of mSlurp, mStaticExec:
|
||||||
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
||||||
of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2,-1))")
|
of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))")
|
||||||
of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
||||||
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
||||||
of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
||||||
|
|
@ -1532,6 +1552,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
genSym(p, n, r)
|
genSym(p, n, r)
|
||||||
of nkCharLit..nkInt64Lit:
|
of nkCharLit..nkInt64Lit:
|
||||||
r.res = toRope(n.intVal)
|
r.res = toRope(n.intVal)
|
||||||
|
r.kind = resExpr
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
if isEmptyType(n.typ):
|
if isEmptyType(n.typ):
|
||||||
discard
|
discard
|
||||||
|
|
@ -1539,8 +1560,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
r.address = toRope"null" | toRope"nil"
|
r.address = toRope"null" | toRope"nil"
|
||||||
r.res = toRope"0"
|
r.res = toRope"0"
|
||||||
|
r.kind = resExpr
|
||||||
else:
|
else:
|
||||||
r.res = toRope"null" | toRope"nil"
|
r.res = toRope"null" | toRope"nil"
|
||||||
|
r.kind = resExpr
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
||||||
useMagic(p, "cstrToNimstr")
|
useMagic(p, "cstrToNimstr")
|
||||||
|
|
@ -1556,6 +1579,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if f > 0.0: r.res = toRope"Infinity"
|
if f > 0.0: r.res = toRope"Infinity"
|
||||||
else: r.res = toRope"-Infinity"
|
else: r.res = toRope"-Infinity"
|
||||||
else: r.res = toRope(f.toStrMaxPrecision)
|
else: r.res = toRope(f.toStrMaxPrecision)
|
||||||
|
r.kind = resExpr
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
||||||
genMagic(p, n, r)
|
genMagic(p, n, r)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -40,7 +40,7 @@ type
|
||||||
tkFinally, tkFor, tkFrom,
|
tkFinally, tkFor, tkFrom,
|
||||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||||
tkIs, tkIsnot, tkIterator,
|
tkIs, tkIsnot, tkIterator,
|
||||||
tkLambda, tkLet,
|
tkLet,
|
||||||
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
||||||
tkObject, tkOf, tkOr, tkOut,
|
tkObject, tkOf, tkOr, tkOut,
|
||||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
|
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
|
||||||
|
|
@ -75,7 +75,7 @@ const
|
||||||
"elif", "else", "end", "enum", "except", "export",
|
"elif", "else", "end", "enum", "except", "export",
|
||||||
"finally", "for", "from", "generic", "if",
|
"finally", "for", "from", "generic", "if",
|
||||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||||
"lambda", "let",
|
"let",
|
||||||
"macro", "method", "mixin", "mod",
|
"macro", "method", "mixin", "mod",
|
||||||
"nil", "not", "notin", "object", "of", "or",
|
"nil", "not", "notin", "object", "of", "or",
|
||||||
"out", "proc", "ptr", "raise", "ref", "return",
|
"out", "proc", "ptr", "raise", "ref", "return",
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements a generic doubled linked list.
|
# This module implements a generic doubled linked list.
|
||||||
|
# TODO Remove this and replace it with something sensible
|
||||||
|
import os
|
||||||
type
|
type
|
||||||
PListEntry* = ref TListEntry
|
PListEntry* = ref TListEntry
|
||||||
TListEntry* = object of TObject
|
TListEntry* = object of TObject
|
||||||
|
|
@ -103,11 +104,12 @@ proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
|
||||||
entry.next = list.head
|
entry.next = list.head
|
||||||
list.head = entry
|
list.head = entry
|
||||||
|
|
||||||
proc excludeStr*(list: var TLinkedList, data: string) =
|
proc excludePath*(list: var TLinkedList, data: string) =
|
||||||
var it = list.head
|
var it = list.head
|
||||||
while it != nil:
|
while it != nil:
|
||||||
let nxt = it.next
|
let nxt = it.next
|
||||||
if PStrEntry(it).data == data: remove(list, it)
|
if cmpPaths(PStrEntry(it).data, data) == 0:
|
||||||
|
remove(list, it)
|
||||||
it = nxt
|
it = nxt
|
||||||
|
|
||||||
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ proc llStreamClose(s: PLLStream) =
|
||||||
of llsFile:
|
of llsFile:
|
||||||
close(s.f)
|
close(s.f)
|
||||||
|
|
||||||
when not defined(readLineFromStdin):
|
when not declared(readLineFromStdin):
|
||||||
# fallback implementation:
|
# fallback implementation:
|
||||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||||
renderer, wordrecg, idgen
|
renderer, wordrecg, idgen, nimfix.prettybase
|
||||||
|
|
||||||
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
||||||
|
|
||||||
|
|
@ -40,11 +40,8 @@ proc considerQuotedIdent*(n: PNode): PIdent =
|
||||||
template addSym*(scope: PScope, s: PSym) =
|
template addSym*(scope: PScope, s: PSym) =
|
||||||
strTableAdd(scope.symbols, s)
|
strTableAdd(scope.symbols, s)
|
||||||
|
|
||||||
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
|
proc addUniqueSym*(scope: PScope, s: PSym): bool =
|
||||||
if strTableIncl(scope.symbols, s):
|
result = not strTableIncl(scope.symbols, s)
|
||||||
result = Failure
|
|
||||||
else:
|
|
||||||
result = Success
|
|
||||||
|
|
||||||
proc openScope*(c: PContext): PScope {.discardable.} =
|
proc openScope*(c: PContext): PScope {.discardable.} =
|
||||||
result = PScope(parent: c.currentScope,
|
result = PScope(parent: c.currentScope,
|
||||||
|
|
@ -65,6 +62,17 @@ iterator walkScopes*(scope: PScope): PScope =
|
||||||
yield current
|
yield current
|
||||||
current = current.parent
|
current = current.parent
|
||||||
|
|
||||||
|
proc skipAlias*(s: PSym; n: PNode): PSym =
|
||||||
|
if s == nil or s.kind != skAlias:
|
||||||
|
result = s
|
||||||
|
else:
|
||||||
|
result = s.owner
|
||||||
|
if gCmd == cmdPretty:
|
||||||
|
prettybase.replaceDeprecated(n.info, s, result)
|
||||||
|
else:
|
||||||
|
message(n.info, warnDeprecated, "use " & result.name.s & " instead; " &
|
||||||
|
s.name.s)
|
||||||
|
|
||||||
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
|
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
|
||||||
result = strTableGet(c.currentScope.symbols, s)
|
result = strTableGet(c.currentScope.symbols, s)
|
||||||
|
|
||||||
|
|
@ -139,14 +147,14 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
|
||||||
localError(info, errAttemptToRedefine, s)
|
localError(info, errAttemptToRedefine, s)
|
||||||
|
|
||||||
proc addDecl*(c: PContext, sym: PSym) =
|
proc addDecl*(c: PContext, sym: PSym) =
|
||||||
if c.currentScope.addUniqueSym(sym) == Failure:
|
if not c.currentScope.addUniqueSym(sym):
|
||||||
wrongRedefinition(sym.info, sym.name.s)
|
wrongRedefinition(sym.info, sym.name.s)
|
||||||
|
|
||||||
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
||||||
discard c.currentScope.addUniqueSym(sym)
|
discard c.currentScope.addUniqueSym(sym)
|
||||||
|
|
||||||
proc addDeclAt*(scope: PScope, sym: PSym) =
|
proc addDeclAt*(scope: PScope, sym: PSym) =
|
||||||
if scope.addUniqueSym(sym) == Failure:
|
if not scope.addUniqueSym(sym):
|
||||||
wrongRedefinition(sym.info, sym.name.s)
|
wrongRedefinition(sym.info, sym.name.s)
|
||||||
|
|
||||||
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||||
|
|
@ -163,7 +171,7 @@ proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
|
||||||
if fn.kind notin OverloadableSyms:
|
if fn.kind notin OverloadableSyms:
|
||||||
internalError(fn.info, "addOverloadableSymAt")
|
internalError(fn.info, "addOverloadableSymAt")
|
||||||
return
|
return
|
||||||
var check = strTableGet(scope.symbols, fn.name)
|
let check = strTableGet(scope.symbols, fn.name)
|
||||||
if check != nil and check.kind notin OverloadableSyms:
|
if check != nil and check.kind notin OverloadableSyms:
|
||||||
wrongRedefinition(fn.info, fn.name.s)
|
wrongRedefinition(fn.info, fn.name.s)
|
||||||
else:
|
else:
|
||||||
|
|
@ -179,20 +187,41 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||||
addOverloadableSymAt(scope, sym)
|
addOverloadableSymAt(scope, sym)
|
||||||
addInterfaceDeclAux(c, sym)
|
addInterfaceDeclAux(c, sym)
|
||||||
|
|
||||||
|
when defined(nimfix):
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
# when we cannot find the identifier, retry with a changed identifer:
|
||||||
|
proc altSpelling(x: PIdent): PIdent =
|
||||||
|
case x.s[0]
|
||||||
|
of 'A'..'Z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
|
||||||
|
of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
|
||||||
|
else: result = x
|
||||||
|
|
||||||
|
template fixSpelling(n: PNode; ident: PIdent; op: expr) =
|
||||||
|
let alt = ident.altSpelling
|
||||||
|
result = op(c, alt).skipAlias(n)
|
||||||
|
if result != nil:
|
||||||
|
prettybase.replaceDeprecated(n.info, ident, alt)
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
|
||||||
|
|
||||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
# Looks up a symbol. Generates an error in case of nil.
|
# Looks up a symbol. Generates an error in case of nil.
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent:
|
of nkIdent:
|
||||||
result = searchInScopes(c, n.ident)
|
result = searchInScopes(c, n.ident).skipAlias(n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
fixSpelling(n, n.ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
of nkAccQuoted:
|
of nkAccQuoted:
|
||||||
var ident = considerQuotedIdent(n)
|
var ident = considerQuotedIdent(n)
|
||||||
result = searchInScopes(c, ident)
|
result = searchInScopes(c, ident).skipAlias(n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
fixSpelling(n, ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
else:
|
else:
|
||||||
|
|
@ -210,8 +239,9 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
var ident = considerQuotedIdent(n)
|
var ident = considerQuotedIdent(n)
|
||||||
result = searchInScopes(c, ident)
|
result = searchInScopes(c, ident).skipAlias(n)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
|
fixSpelling(n, ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
elif checkAmbiguity in flags and result != nil and
|
elif checkAmbiguity in flags and result != nil and
|
||||||
|
|
@ -224,7 +254,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
result = nil
|
result = nil
|
||||||
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
||||||
if (m != nil) and (m.kind == skModule):
|
if m != nil and m.kind == skModule:
|
||||||
var ident: PIdent = nil
|
var ident: PIdent = nil
|
||||||
if n.sons[1].kind == nkIdent:
|
if n.sons[1].kind == nkIdent:
|
||||||
ident = n.sons[1].ident
|
ident = n.sons[1].ident
|
||||||
|
|
@ -232,10 +262,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
ident = considerQuotedIdent(n.sons[1])
|
ident = considerQuotedIdent(n.sons[1])
|
||||||
if ident != nil:
|
if ident != nil:
|
||||||
if m == c.module:
|
if m == c.module:
|
||||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
|
||||||
else:
|
else:
|
||||||
result = strTableGet(m.tab, ident)
|
result = strTableGet(m.tab, ident).skipAlias(n)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
|
fixSpelling(n.sons[1], ident, searchInScopes)
|
||||||
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
elif n.sons[1].kind == nkSym:
|
elif n.sons[1].kind == nkSym:
|
||||||
|
|
@ -256,7 +287,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
o.scope = c.currentScope
|
o.scope = c.currentScope
|
||||||
o.mode = oimNoQualifier
|
o.mode = oimNoQualifier
|
||||||
while true:
|
while true:
|
||||||
result = initIdentIter(o.it, o.scope.symbols, ident)
|
result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
@ -277,10 +308,11 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
if ident != nil:
|
if ident != nil:
|
||||||
if o.m == c.module:
|
if o.m == c.module:
|
||||||
# a module may access its private members:
|
# a module may access its private members:
|
||||||
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
|
result = initIdentIter(o.it, c.topLevelScope.symbols,
|
||||||
|
ident).skipAlias(n)
|
||||||
o.mode = oimSelfModule
|
o.mode = oimSelfModule
|
||||||
else:
|
else:
|
||||||
result = initIdentIter(o.it, o.m.tab, ident)
|
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
|
||||||
else:
|
else:
|
||||||
localError(n.sons[1].info, errIdentifierExpected,
|
localError(n.sons[1].info, errIdentifierExpected,
|
||||||
renderTree(n.sons[1]))
|
renderTree(n.sons[1]))
|
||||||
|
|
@ -307,18 +339,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
result = nil
|
result = nil
|
||||||
of oimNoQualifier:
|
of oimNoQualifier:
|
||||||
if o.scope != nil:
|
if o.scope != nil:
|
||||||
result = nextIdentIter(o.it, o.scope.symbols)
|
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
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).skipAlias(n)
|
||||||
# BUGFIX: o.it.name <-> n.ident
|
# BUGFIX: o.it.name <-> n.ident
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
of oimSelfModule:
|
of oimSelfModule:
|
||||||
result = nextIdentIter(o.it, c.topLevelScope.symbols)
|
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
|
||||||
of oimOtherModule:
|
of oimOtherModule:
|
||||||
result = nextIdentIter(o.it, o.m.tab)
|
result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
|
||||||
of oimSymChoice:
|
of oimSymChoice:
|
||||||
if o.symChoiceIndex < sonsLen(n):
|
if o.symChoiceIndex < sonsLen(n):
|
||||||
result = n.sons[o.symChoiceIndex].sym
|
result = n.sons[o.symChoiceIndex].sym
|
||||||
|
|
@ -329,31 +361,27 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
o.mode = oimSymChoiceLocalLookup
|
o.mode = oimSymChoiceLocalLookup
|
||||||
o.scope = c.currentScope
|
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)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
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)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
of oimSymChoiceLocalLookup:
|
of oimSymChoiceLocalLookup:
|
||||||
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
|
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
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)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
|
|
||||||
if result != nil and result.kind == skStub: loadStub(result)
|
if result != nil and result.kind == skStub: loadStub(result)
|
||||||
|
|
||||||
when false:
|
proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
|
||||||
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
|
flags: TSymFlags = {}): PSym =
|
||||||
flags = {checkUndeclared}): PSym =
|
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
result = initOverloadIter(o, c, n)
|
var a = initOverloadIter(o, c, n)
|
||||||
var a = result
|
|
||||||
while a != nil:
|
while a != nil:
|
||||||
if sfImmediate in a.flags: return a
|
if a.kind == kind and flags <= a.flags:
|
||||||
|
return a
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
if result == nil and checkUndeclared in flags:
|
|
||||||
localError(n.info, errUndeclaredIdentifier, n.considerQuotedIdent.s)
|
|
||||||
result = errorSym(c, n)
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||||
|
|
||||||
result.add newAsgnStmt(newSymNode(temp), value)
|
result.add newAsgnStmt(newSymNode(temp), value)
|
||||||
for i in 0 .. n.len-3:
|
for i in 0 .. n.len-3:
|
||||||
|
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
|
||||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
||||||
|
|
||||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||||
|
|
@ -64,6 +65,22 @@ proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||||
incl result.flags, tfFinal
|
incl result.flags, tfFinal
|
||||||
result.n = newNodeI(nkRecList, info)
|
result.n = newNodeI(nkRecList, info)
|
||||||
|
|
||||||
|
proc rawAddField*(obj: PType; field: PSym) =
|
||||||
|
assert field.kind == skField
|
||||||
|
field.position = sonsLen(obj.n)
|
||||||
|
addSon(obj.n, newSymNode(field))
|
||||||
|
|
||||||
|
proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
|
||||||
|
# returns a[].field as a node
|
||||||
|
assert field.kind == skField
|
||||||
|
var deref = newNodeI(nkHiddenDeref, info)
|
||||||
|
deref.typ = a.typ.skipTypes(abstractInst).sons[0]
|
||||||
|
addSon(deref, a)
|
||||||
|
result = newNodeI(nkDotExpr, info)
|
||||||
|
addSon(result, deref)
|
||||||
|
addSon(result, newSymNode(field))
|
||||||
|
result.typ = field.typ
|
||||||
|
|
||||||
proc addField*(obj: PType; s: PSym) =
|
proc addField*(obj: PType; s: PSym) =
|
||||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
# 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.
|
# This is hacky but the clean solution is much more complex than it looks.
|
||||||
|
|
@ -74,6 +91,16 @@ proc addField*(obj: PType; s: PSym) =
|
||||||
field.position = sonsLen(obj.n)
|
field.position = sonsLen(obj.n)
|
||||||
addSon(obj.n, newSymNode(field))
|
addSon(obj.n, newSymNode(field))
|
||||||
|
|
||||||
|
proc addUniqueField*(obj: PType; s: PSym) =
|
||||||
|
let fieldName = getIdent(s.name.s & $s.id)
|
||||||
|
if lookupInRecord(obj.n, fieldName) == nil:
|
||||||
|
var field = newSym(skField, fieldName, s.owner, s.info)
|
||||||
|
let t = skipIntLit(s.typ)
|
||||||
|
field.typ = t
|
||||||
|
assert t.kind != tyStmt
|
||||||
|
field.position = sonsLen(obj.n)
|
||||||
|
addSon(obj.n, newSymNode(field))
|
||||||
|
|
||||||
proc newDotExpr(obj, b: PSym): PNode =
|
proc newDotExpr(obj, b: PSym): PNode =
|
||||||
result = newNodeI(nkDotExpr, obj.info)
|
result = newNodeI(nkDotExpr, obj.info)
|
||||||
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
|
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
|
||||||
|
|
@ -95,13 +122,28 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
if t == nil: break
|
if t == nil: break
|
||||||
t = t.skipTypes(abstractInst)
|
t = t.skipTypes(abstractInst)
|
||||||
assert field != nil, b
|
#if field == nil:
|
||||||
|
# echo "FIELD ", b
|
||||||
|
# debug deref.typ
|
||||||
|
internalAssert field != nil
|
||||||
addSon(deref, a)
|
addSon(deref, a)
|
||||||
result = newNodeI(nkDotExpr, info)
|
result = newNodeI(nkDotExpr, info)
|
||||||
addSon(result, deref)
|
addSon(result, deref)
|
||||||
addSon(result, newSymNode(field))
|
addSon(result, newSymNode(field))
|
||||||
result.typ = field.typ
|
result.typ = field.typ
|
||||||
|
|
||||||
|
proc getFieldFromObj*(t: PType; v: PSym): PSym =
|
||||||
|
assert v.kind != skField
|
||||||
|
let fieldName = getIdent(v.name.s & $v.id)
|
||||||
|
var t = t
|
||||||
|
while true:
|
||||||
|
assert t.kind == tyObject
|
||||||
|
result = getSymFromList(t.n, fieldName)
|
||||||
|
if result != nil: break
|
||||||
|
t = t.sons[0]
|
||||||
|
if t == nil: break
|
||||||
|
t = t.skipTypes(abstractInst)
|
||||||
|
|
||||||
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
|
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||||
# returns a[].b as a node
|
# returns a[].b as a node
|
||||||
result = indirectAccess(a, b.name.s & $b.id, info)
|
result = indirectAccess(a, b.name.s & $b.id, info)
|
||||||
|
|
@ -144,14 +186,14 @@ proc callProc(a: PNode): PNode =
|
||||||
# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter
|
# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter
|
||||||
# - not in a parallel environment --> requires a flowVar for memory safety
|
# - not in a parallel environment --> requires a flowVar for memory safety
|
||||||
type
|
type
|
||||||
TSpawnResult = enum
|
TSpawnResult* = enum
|
||||||
srVoid, srFlowVar, srByVar
|
srVoid, srFlowVar, srByVar
|
||||||
TFlowVarKind = enum
|
TFlowVarKind = enum
|
||||||
fvInvalid # invalid type T for 'FlowVar[T]'
|
fvInvalid # invalid type T for 'FlowVar[T]'
|
||||||
fvGC # FlowVar of a GC'ed type
|
fvGC # FlowVar of a GC'ed type
|
||||||
fvBlob # FlowVar of a blob type
|
fvBlob # FlowVar of a blob type
|
||||||
|
|
||||||
proc spawnResult(t: PType; inParallel: bool): TSpawnResult =
|
proc spawnResult*(t: PType; inParallel: bool): TSpawnResult =
|
||||||
if t.isEmptyType: srVoid
|
if t.isEmptyType: srVoid
|
||||||
elif inParallel and not containsGarbageCollectedRef(t): srByVar
|
elif inParallel and not containsGarbageCollectedRef(t): srByVar
|
||||||
else: srFlowVar
|
else: srFlowVar
|
||||||
|
|
@ -161,7 +203,8 @@ proc flowVarKind(t: PType): TFlowVarKind =
|
||||||
elif containsGarbageCollectedRef(t): fvInvalid
|
elif containsGarbageCollectedRef(t): fvInvalid
|
||||||
else: fvBlob
|
else: fvBlob
|
||||||
|
|
||||||
proc addLocalVar(varSection: PNode; owner: PSym; typ: PType; v: PNode): PSym =
|
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
||||||
|
v: PNode): PSym =
|
||||||
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
|
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
|
|
@ -169,8 +212,14 @@ proc addLocalVar(varSection: PNode; owner: PSym; typ: PType; v: PNode): PSym =
|
||||||
var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
|
var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
|
||||||
vpart.sons[0] = newSymNode(result)
|
vpart.sons[0] = newSymNode(result)
|
||||||
vpart.sons[1] = ast.emptyNode
|
vpart.sons[1] = ast.emptyNode
|
||||||
vpart.sons[2] = v
|
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
|
||||||
varSection.add vpart
|
varSection.add vpart
|
||||||
|
if varInit != nil:
|
||||||
|
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||||
|
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
||||||
|
deepCopyCall.sons[1] = newSymNode(result)
|
||||||
|
deepCopyCall.sons[2] = v
|
||||||
|
varInit.add deepCopyCall
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
We generate roughly this:
|
We generate roughly this:
|
||||||
|
|
@ -203,24 +252,24 @@ stmtList:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
varSection, call, barrier, fv: PNode;
|
varSection, varInit, call, barrier, fv: PNode;
|
||||||
spawnKind: TSpawnResult): PSym =
|
spawnKind: TSpawnResult): PSym =
|
||||||
var body = newNodeI(nkStmtList, f.info)
|
var body = newNodeI(nkStmtList, f.info)
|
||||||
var threadLocalBarrier: PSym
|
var threadLocalBarrier: PSym
|
||||||
if barrier != nil:
|
if barrier != nil:
|
||||||
var varSection = newNodeI(nkVarSection, barrier.info)
|
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
||||||
threadLocalBarrier = addLocalVar(varSection, argsParam.owner,
|
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
|
||||||
barrier.typ, barrier)
|
barrier.typ, barrier)
|
||||||
body.add varSection
|
body.add varSection2
|
||||||
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
||||||
var threadLocalProm: PSym
|
var threadLocalProm: PSym
|
||||||
if spawnKind == srByVar:
|
if spawnKind == srByVar:
|
||||||
threadLocalProm = addLocalVar(varSection, argsParam.owner, fv.typ, fv)
|
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
||||||
elif fv != nil:
|
elif fv != nil:
|
||||||
internalAssert fv.typ.kind == tyGenericInst
|
internalAssert fv.typ.kind == tyGenericInst
|
||||||
threadLocalProm = addLocalVar(varSection, argsParam.owner, fv.typ, fv)
|
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
||||||
|
|
||||||
body.add varSection
|
body.add varSection
|
||||||
|
body.add varInit
|
||||||
if fv != nil and spawnKind != srByVar:
|
if fv != nil and spawnKind != srByVar:
|
||||||
# generate:
|
# generate:
|
||||||
# fv.owner = threadParam
|
# fv.owner = threadParam
|
||||||
|
|
@ -273,7 +322,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
|
||||||
result.typ.rawAddSon(objType)
|
result.typ.rawAddSon(objType)
|
||||||
|
|
||||||
proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
|
proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
|
||||||
castExpr, call, varSection, result: PNode) =
|
castExpr, call,
|
||||||
|
varSection, varInit, result: PNode) =
|
||||||
let formals = n[0].typ.n
|
let formals = n[0].typ.n
|
||||||
let tmpName = getIdent(genPrefix)
|
let tmpName = getIdent(genPrefix)
|
||||||
for i in 1 .. <n.len:
|
for i in 1 .. <n.len:
|
||||||
|
|
@ -282,8 +332,8 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
|
||||||
var argType = n[i].typ.skipTypes(abstractInst)
|
var argType = n[i].typ.skipTypes(abstractInst)
|
||||||
if i < formals.len and formals[i].typ.kind == tyVar:
|
if i < formals.len and formals[i].typ.kind == tyVar:
|
||||||
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
||||||
elif containsTyRef(argType):
|
#elif containsTyRef(argType):
|
||||||
localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
# localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||||
|
|
||||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||||
var field = newSym(skField, fieldname, objType.owner, n.info)
|
var field = newSym(skField, fieldname, objType.owner, n.info)
|
||||||
|
|
@ -291,7 +341,7 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
|
||||||
objType.addField(field)
|
objType.addField(field)
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||||
|
|
||||||
let temp = addLocalVar(varSection, objType.owner, argType,
|
let temp = addLocalVar(varSection, varInit, objType.owner, argType,
|
||||||
indirectAccess(castExpr, field, n.info))
|
indirectAccess(castExpr, field, n.info))
|
||||||
call.add(newSymNode(temp))
|
call.add(newSymNode(temp))
|
||||||
|
|
||||||
|
|
@ -326,7 +376,8 @@ proc genHigh(n: PNode): PNode =
|
||||||
result.sons[1] = n
|
result.sons[1] = n
|
||||||
|
|
||||||
proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
castExpr, call, varSection, result: PNode) =
|
castExpr, call,
|
||||||
|
varSection, varInit, result: PNode) =
|
||||||
let formals = n[0].typ.n
|
let formals = n[0].typ.n
|
||||||
let tmpName = getIdent(genPrefix)
|
let tmpName = getIdent(genPrefix)
|
||||||
# we need to copy the foreign scratch object fields into local variables
|
# we need to copy the foreign scratch object fields into local variables
|
||||||
|
|
@ -335,8 +386,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
let n = n[i]
|
let n = n[i]
|
||||||
let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
|
let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
|
||||||
abstractInst)
|
abstractInst)
|
||||||
if containsTyRef(argType):
|
#if containsTyRef(argType):
|
||||||
localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
|
# localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||||
|
|
||||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||||
var field = newSym(skField, fieldname, objType.owner, n.info)
|
var field = newSym(skField, fieldname, objType.owner, n.info)
|
||||||
|
|
@ -362,7 +413,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
||||||
|
|
||||||
let threadLocal = addLocalVar(varSection, objType.owner, fieldA.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
|
||||||
indirectAccess(castExpr, fieldA, n.info))
|
indirectAccess(castExpr, fieldA, n.info))
|
||||||
slice.sons[2] = threadLocal.newSymNode
|
slice.sons[2] = threadLocal.newSymNode
|
||||||
else:
|
else:
|
||||||
|
|
@ -376,7 +427,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
# the array itself does not need to go through a thread local variable:
|
# the array itself does not need to go through a thread local variable:
|
||||||
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
||||||
|
|
||||||
let threadLocal = addLocalVar(varSection, objType.owner, fieldB.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
|
||||||
indirectAccess(castExpr, fieldB, n.info))
|
indirectAccess(castExpr, fieldB, n.info))
|
||||||
slice.sons[3] = threadLocal.newSymNode
|
slice.sons[3] = threadLocal.newSymNode
|
||||||
call.add slice
|
call.add slice
|
||||||
|
|
@ -387,7 +438,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
field.typ = a.typ
|
field.typ = a.typ
|
||||||
objType.addField(field)
|
objType.addField(field)
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||||
let threadLocal = addLocalVar(varSection, objType.owner, field.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
|
||||||
indirectAccess(castExpr, field, n.info))
|
indirectAccess(castExpr, field, n.info))
|
||||||
call.add(genDeref(threadLocal.newSymNode))
|
call.add(genDeref(threadLocal.newSymNode))
|
||||||
else:
|
else:
|
||||||
|
|
@ -395,7 +446,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
field.typ = argType
|
field.typ = argType
|
||||||
objType.addField(field)
|
objType.addField(field)
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
||||||
let threadLocal = addLocalVar(varSection, objType.owner, field.typ,
|
let threadLocal = addLocalVar(varSection, varInit,
|
||||||
|
objType.owner, field.typ,
|
||||||
indirectAccess(castExpr, field, n.info))
|
indirectAccess(castExpr, field, n.info))
|
||||||
call.add(threadLocal.newSymNode)
|
call.add(threadLocal.newSymNode)
|
||||||
|
|
||||||
|
|
@ -463,10 +515,13 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||||
|
|
||||||
call.add(fn)
|
call.add(fn)
|
||||||
var varSection = newNodeI(nkVarSection, n.info)
|
var varSection = newNodeI(nkVarSection, n.info)
|
||||||
|
var varInit = newNodeI(nkStmtList, n.info)
|
||||||
if barrier.isNil:
|
if barrier.isNil:
|
||||||
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, varSection, result)
|
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
|
||||||
|
varSection, varInit, result)
|
||||||
else:
|
else:
|
||||||
setupArgsForParallelism(n, objType, scratchObj, castExpr, call, varSection, result)
|
setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
|
||||||
|
varSection, varInit, result)
|
||||||
|
|
||||||
var barrierAsExpr: PNode = nil
|
var barrierAsExpr: PNode = nil
|
||||||
if barrier != nil:
|
if barrier != nil:
|
||||||
|
|
@ -498,7 +553,8 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
|
||||||
|
|
||||||
let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, call,
|
let wrapper = createWrapperProc(fn, threadParam, argsParam,
|
||||||
|
varSection, varInit, call,
|
||||||
barrierAsExpr, fvAsExpr, spawnKind)
|
barrierAsExpr, fvAsExpr, spawnKind)
|
||||||
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
||||||
genAddrOf(scratchObj.newSymNode))
|
genAddrOf(scratchObj.newSymNode))
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ var
|
||||||
gSysTypes: array[TTypeKind, PType]
|
gSysTypes: array[TTypeKind, PType]
|
||||||
compilerprocs: TStrTable
|
compilerprocs: TStrTable
|
||||||
|
|
||||||
|
proc nilOrSysInt*: PType = gSysTypes[tyInt]
|
||||||
|
|
||||||
proc registerSysType(t: PType) =
|
proc registerSysType(t: PType) =
|
||||||
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
|
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
|
||||||
|
|
||||||
|
|
|
||||||
106
compiler/nimfix/nimfix.nim
Normal file
106
compiler/nimfix/nimfix.nim
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
|
||||||
|
|
||||||
|
import strutils, os, parseopt
|
||||||
|
import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
|
||||||
|
extccomp, condsyms, lists
|
||||||
|
|
||||||
|
const Usage = """
|
||||||
|
Nimfix - Tool to patch Nim code
|
||||||
|
Usage:
|
||||||
|
nimfix [options] projectflie.nim
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--overwriteFiles:on|off overwrite the original nim files.
|
||||||
|
DEFAULT is ON!
|
||||||
|
--wholeProject overwrite every processed file.
|
||||||
|
--checkExtern:on|off style check also extern names
|
||||||
|
--styleCheck:on|off|auto performs style checking for identifiers
|
||||||
|
and suggests an alternative spelling;
|
||||||
|
'auto' corrects the spelling.
|
||||||
|
|
||||||
|
In addition, all command line options of Nim are supported.
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc mainCommand =
|
||||||
|
#msgs.gErrorMax = high(int) # do not stop after first error
|
||||||
|
registerPass verbosePass
|
||||||
|
registerPass semPass
|
||||||
|
gCmd = cmdPretty
|
||||||
|
appendStr(searchPaths, options.libpath)
|
||||||
|
if gProjectFull.len != 0:
|
||||||
|
# current path is always looked first for modules
|
||||||
|
prependStr(searchPaths, gProjectPath)
|
||||||
|
|
||||||
|
compileProject()
|
||||||
|
pretty.overwriteFiles()
|
||||||
|
|
||||||
|
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
|
var p = parseopt.initOptParser(cmd)
|
||||||
|
var argsCount = 0
|
||||||
|
gOnlyMainfile = true
|
||||||
|
while true:
|
||||||
|
parseopt.next(p)
|
||||||
|
case p.kind
|
||||||
|
of cmdEnd: break
|
||||||
|
of cmdLongoption, cmdShortOption:
|
||||||
|
case p.key.normalize
|
||||||
|
of "overwritefiles":
|
||||||
|
case p.val.normalize
|
||||||
|
of "on": gOverWrite = true
|
||||||
|
of "off": gOverWrite = false
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "checkextern":
|
||||||
|
case p.val.normalize
|
||||||
|
of "on": gCheckExtern = true
|
||||||
|
of "off": gCheckExtern = false
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "stylecheck":
|
||||||
|
case p.val.normalize
|
||||||
|
of "off": gStyleCheck = StyleCheck.None
|
||||||
|
of "on": gStyleCheck = StyleCheck.Warn
|
||||||
|
of "auto": gStyleCheck = StyleCheck.Auto
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "wholeproject": gOnlyMainfile = false
|
||||||
|
else:
|
||||||
|
processSwitch(pass, p)
|
||||||
|
of cmdArgument:
|
||||||
|
options.gProjectName = unixToNativePath(p.key)
|
||||||
|
# if processArgument(pass, p, argsCount): break
|
||||||
|
|
||||||
|
proc handleCmdLine() =
|
||||||
|
if paramCount() == 0:
|
||||||
|
stdout.writeln(Usage)
|
||||||
|
else:
|
||||||
|
processCmdLine(passCmd1, "")
|
||||||
|
if gProjectName != "":
|
||||||
|
try:
|
||||||
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
|
except OSError:
|
||||||
|
gProjectFull = gProjectName
|
||||||
|
var p = splitFile(gProjectFull)
|
||||||
|
gProjectPath = p.dir
|
||||||
|
gProjectName = p.name
|
||||||
|
else:
|
||||||
|
gProjectPath = getCurrentDir()
|
||||||
|
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()
|
||||||
|
|
||||||
|
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
|
GC_disableMarkAndSweep()
|
||||||
|
|
||||||
|
condsyms.initDefines()
|
||||||
|
defineSymbol "nimfix"
|
||||||
|
handleCmdline()
|
||||||
17
compiler/nimfix/nimfix.nim.cfg
Normal file
17
compiler/nimfix/nimfix.nim.cfg
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Special configuration file for the Nim project
|
||||||
|
# gc:markAndSweep
|
||||||
|
|
||||||
|
hint[XDeclaredButNotUsed]:off
|
||||||
|
path:"$projectPath/../.."
|
||||||
|
|
||||||
|
path:"$lib/packages/docutils"
|
||||||
|
path:"$nim/compiler"
|
||||||
|
|
||||||
|
define:useStdoutAsStdmsg
|
||||||
|
symbol:nimfix
|
||||||
|
define:nimfix
|
||||||
|
|
||||||
|
cs:partial
|
||||||
|
#define:useNodeIds
|
||||||
|
define:booting
|
||||||
|
define:noDocgen
|
||||||
152
compiler/nimfix/pretty.nim
Normal file
152
compiler/nimfix/pretty.nim
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module implements the code "prettifier". This is part of the toolchain
|
||||||
|
## to convert Nim code into a consistent style.
|
||||||
|
|
||||||
|
import
|
||||||
|
strutils, os, options, ast, astalgo, msgs, ropes, idents,
|
||||||
|
intsets, strtabs, semdata, prettybase
|
||||||
|
|
||||||
|
type
|
||||||
|
StyleCheck* {.pure.} = enum None, Warn, Auto
|
||||||
|
|
||||||
|
var
|
||||||
|
gOverWrite* = true
|
||||||
|
gStyleCheck*: StyleCheck
|
||||||
|
gCheckExtern*, gOnlyMainfile*: bool
|
||||||
|
|
||||||
|
proc overwriteFiles*() =
|
||||||
|
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
|
||||||
|
for i in 0 .. high(gSourceFiles):
|
||||||
|
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
|
||||||
|
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
|
||||||
|
let newFile = if gOverWrite: gSourceFiles[i].fullpath
|
||||||
|
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
|
||||||
|
try:
|
||||||
|
var f = open(newFile, fmWrite)
|
||||||
|
for line in gSourceFiles[i].lines:
|
||||||
|
if doStrip:
|
||||||
|
f.write line.strip(leading = false, trailing = true)
|
||||||
|
else:
|
||||||
|
f.write line
|
||||||
|
f.write(gSourceFiles[i].newline)
|
||||||
|
f.close
|
||||||
|
except IOError:
|
||||||
|
rawMessage(errCannotOpenFile, newFile)
|
||||||
|
|
||||||
|
proc `=~`(s: string, a: openArray[string]): bool =
|
||||||
|
for x in a:
|
||||||
|
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:
|
||||||
|
# Types should start with a capital unless builtins like 'int' etc.:
|
||||||
|
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
|
||||||
|
"char", "byte", "bool", "openArray", "seq", "array", "void",
|
||||||
|
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||||
|
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
|
||||||
|
"range", "openarray", "varargs", "set", "cfloat"
|
||||||
|
]:
|
||||||
|
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'
|
||||||
|
elif '_' in s: result.add(s[i])
|
||||||
|
else: result.add toLower(s[0])
|
||||||
|
inc i
|
||||||
|
while i < s.len:
|
||||||
|
if 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:
|
||||||
|
result.add s[i]
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc replaceInFile(info: TLineInfo; newName: string) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = min(info.col.int, line.len)
|
||||||
|
if first < 0: return
|
||||||
|
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||||
|
while first > 0 and line[first-1] in prettybase.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)
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
|
||||||
|
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
||||||
|
let beau = beautifyName(s, k)
|
||||||
|
if s != beau:
|
||||||
|
if gStyleCheck == StyleCheck.Auto:
|
||||||
|
sym.name = getIdent(beau)
|
||||||
|
replaceInFile(info, beau)
|
||||||
|
else:
|
||||||
|
message(info, hintName, beau)
|
||||||
|
|
||||||
|
proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) =
|
||||||
|
# operators stay as they are:
|
||||||
|
if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
|
||||||
|
if k in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||||
|
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
|
||||||
|
checkStyle(info, s.name.s, k, s)
|
||||||
|
|
||||||
|
template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
|
||||||
|
when defined(nimfix):
|
||||||
|
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k)
|
||||||
|
|
||||||
|
template styleCheckDef*(info: TLineInfo; s: PSym) =
|
||||||
|
styleCheckDef(info, s, s.kind)
|
||||||
|
template styleCheckDef*(s: PSym) =
|
||||||
|
styleCheckDef(s.info, s, s.kind)
|
||||||
|
|
||||||
|
proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
|
||||||
|
if 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 prettybase.Letters:
|
||||||
|
return
|
||||||
|
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||||
|
let newName = s.name.s
|
||||||
|
|
||||||
|
replaceInFile(info, newName)
|
||||||
|
#if newName == "File": writeStackTrace()
|
||||||
|
|
||||||
|
template styleCheckUse*(info: TLineInfo; s: PSym) =
|
||||||
|
when defined(nimfix):
|
||||||
|
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s)
|
||||||
93
compiler/nimfix/prettybase.nim
Normal file
93
compiler/nimfix/prettybase.nim
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
import ast, msgs, strutils, idents, lexbase, streams
|
||||||
|
from os import splitFile
|
||||||
|
|
||||||
|
type
|
||||||
|
TSourceFile* = object
|
||||||
|
lines*: seq[string]
|
||||||
|
dirty*, isNimfixFile*: bool
|
||||||
|
fullpath*, newline*: string
|
||||||
|
fileIdx*: int32
|
||||||
|
|
||||||
|
var
|
||||||
|
gSourceFiles*: seq[TSourceFile] = @[]
|
||||||
|
|
||||||
|
proc loadFile*(info: TLineInfo) =
|
||||||
|
let i = info.fileIndex
|
||||||
|
if i >= gSourceFiles.len:
|
||||||
|
gSourceFiles.setLen(i+1)
|
||||||
|
if gSourceFiles[i].lines.isNil:
|
||||||
|
gSourceFiles[i].fileIdx = info.fileIndex
|
||||||
|
gSourceFiles[i].lines = @[]
|
||||||
|
let path = info.toFullPath
|
||||||
|
gSourceFiles[i].fullpath = path
|
||||||
|
gSourceFiles[i].isNimfixFile = path.splitFile.ext == ".nimfix"
|
||||||
|
# we want to die here for IOError:
|
||||||
|
for line in lines(path):
|
||||||
|
gSourceFiles[i].lines.add(line)
|
||||||
|
# extract line ending of the file:
|
||||||
|
var lex: TBaseLexer
|
||||||
|
open(lex, newFileStream(path, fmRead))
|
||||||
|
var pos = lex.bufpos
|
||||||
|
while true:
|
||||||
|
case lex.buf[pos]
|
||||||
|
of '\c':
|
||||||
|
gSourceFiles[i].newline = "\c\L"
|
||||||
|
break
|
||||||
|
of '\L', '\0':
|
||||||
|
gSourceFiles[i].newline = "\L"
|
||||||
|
break
|
||||||
|
else: discard
|
||||||
|
inc pos
|
||||||
|
close(lex)
|
||||||
|
|
||||||
|
const
|
||||||
|
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||||
|
|
||||||
|
proc identLen*(line: string, start: int): int =
|
||||||
|
while start+result < line.len and line[start+result] in Letters:
|
||||||
|
inc result
|
||||||
|
|
||||||
|
proc differ*(line: string, a, b: int, x: string): bool =
|
||||||
|
let y = line[a..b]
|
||||||
|
result = cmpIgnoreStyle(y, x) == 0 and y != x
|
||||||
|
|
||||||
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = min(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 cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||||
|
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
#if newSym.s == "File": writeStackTrace()
|
||||||
|
|
||||||
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
|
||||||
|
replaceDeprecated(info, oldSym.name, newSym.name)
|
||||||
|
|
||||||
|
proc replaceComment*(info: TLineInfo) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = info.col.int
|
||||||
|
if line[first] != '#': inc first
|
||||||
|
|
||||||
|
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
; This config file holds configuration information about the Nim compiler
|
||||||
|
; and project.
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name: "Nimrod"
|
Name: "Nimrod"
|
||||||
Version: "$version"
|
Version: "$version"
|
||||||
|
|
@ -34,11 +37,11 @@ Files: "config/nimdoc.cfg"
|
||||||
Files: "config/nimdoc.tex.cfg"
|
Files: "config/nimdoc.tex.cfg"
|
||||||
|
|
||||||
[Documentation]
|
[Documentation]
|
||||||
Files: "doc/*.txt"
|
; Files: "doc/*.html"
|
||||||
Files: "doc/*.html"
|
; Files: "doc/*.cfg"
|
||||||
Files: "doc/*.cfg"
|
; Files: "doc/*.pdf"
|
||||||
Files: "doc/*.pdf"
|
; Files: "doc/*.ini"
|
||||||
Files: "doc/*.ini"
|
Files: "doc/overview.html"
|
||||||
Start: "doc/overview.html"
|
Start: "doc/overview.html"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -61,13 +64,9 @@ Files: "compiler/readme.txt"
|
||||||
Files: "compiler/nimrod.ini"
|
Files: "compiler/nimrod.ini"
|
||||||
Files: "compiler/nimrod.cfg"
|
Files: "compiler/nimrod.cfg"
|
||||||
Files: "compiler/*.nim"
|
Files: "compiler/*.nim"
|
||||||
Files: "compiler/c2nim/*.nim"
|
Files: "doc/*.txt"
|
||||||
Files: "compiler/c2nim/*.cfg"
|
Files: "compiler/nimfix/*.nim"
|
||||||
Files: "compiler/pas2nim/*.nim"
|
Files: "compiler/nimfix/*.cfg"
|
||||||
Files: "compiler/pas2nim/*.cfg"
|
|
||||||
|
|
||||||
Files: "build/empty.txt"
|
|
||||||
Files: "bin/empty.txt"
|
|
||||||
|
|
||||||
|
|
||||||
[Lib]
|
[Lib]
|
||||||
|
|
@ -115,17 +114,22 @@ Files: "examples/*.tmpl"
|
||||||
|
|
||||||
[Windows]
|
[Windows]
|
||||||
Files: "bin/nimrod.exe"
|
Files: "bin/nimrod.exe"
|
||||||
|
Files: "bin/nimrod_debug.exe"
|
||||||
Files: "bin/c2nim.exe"
|
Files: "bin/c2nim.exe"
|
||||||
Files: "bin/niminst.exe"
|
Files: "bin/niminst.exe"
|
||||||
Files: "bin/nimgrep.exe"
|
Files: "bin/nimgrep.exe"
|
||||||
|
|
||||||
Files: "dist/*.dll"
|
Files: "dist/*.dll"
|
||||||
Files: "koch.exe"
|
Files: "koch.exe"
|
||||||
Files: "dist/mingw"
|
; Files: "dist/mingw"
|
||||||
Files: "start.bat"
|
Files: "start.bat"
|
||||||
BinPath: r"bin;dist\mingw\bin;dist"
|
BinPath: r"bin;dist\mingw\bin;dist"
|
||||||
InnoSetup: "Yes"
|
|
||||||
|
|
||||||
|
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
|
||||||
|
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip"
|
||||||
|
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
|
||||||
|
Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe"
|
||||||
|
; for now only NSIS supports optional downloads
|
||||||
|
|
||||||
[UnixBin]
|
[UnixBin]
|
||||||
Files: "bin/nimrod"
|
Files: "bin/nimrod"
|
||||||
|
|
@ -140,6 +144,9 @@ UninstallScript: "yes"
|
||||||
path = r"c:\Program Files (x86)\Inno Setup 5\iscc.exe"
|
path = r"c:\Program Files (x86)\Inno Setup 5\iscc.exe"
|
||||||
flags = "/Q"
|
flags = "/Q"
|
||||||
|
|
||||||
|
[NSIS]
|
||||||
|
path = r"c:\Program Files (x86)\NSIS\makensis.exe"
|
||||||
|
flags = "/V0"
|
||||||
|
|
||||||
[C_Compiler]
|
[C_Compiler]
|
||||||
path = r""
|
path = r""
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ proc handleCmdLine() =
|
||||||
if msgs.gErrorCounter == 0:
|
if msgs.gErrorCounter == 0:
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.run()
|
tccgen.run(service.arguments)
|
||||||
if optRun in gGlobalOptions:
|
if optRun in gGlobalOptions:
|
||||||
if gCmd == cmdCompileToJS:
|
if gCmd == cmdCompileToJS:
|
||||||
var ex: string
|
var ex: string
|
||||||
|
|
@ -79,7 +79,7 @@ proc handleCmdLine() =
|
||||||
var ex = quoteShell(binPath)
|
var ex = quoteShell(binPath)
|
||||||
execExternalProgram(ex & ' ' & service.arguments)
|
execExternalProgram(ex & ' ' & service.arguments)
|
||||||
|
|
||||||
when defined(GC_setMaxPause):
|
when declared(GC_setMaxPause):
|
||||||
GC_setMaxPause 2_000
|
GC_setMaxPause 2_000
|
||||||
|
|
||||||
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const
|
||||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||||
VersionMajor* = 0
|
VersionMajor* = 0
|
||||||
VersionMinor* = 9
|
VersionMinor* = 9
|
||||||
VersionPatch* = 5
|
VersionPatch* = 6
|
||||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||||
|
|
||||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ var
|
||||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||||
optHints, optStackTrace, optLineTrace,
|
optHints, optStackTrace, optLineTrace,
|
||||||
optPatterns, optNilCheck}
|
optPatterns, optNilCheck}
|
||||||
gGlobalOptions*: TGlobalOptions = {}
|
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
||||||
gExitcode*: int8
|
gExitcode*: int8
|
||||||
gCmd*: TCommands = cmdNone # the command
|
gCmd*: TCommands = cmdNone # the command
|
||||||
gSelectedGC* = gcRefc # the selected GC
|
gSelectedGC* = gcRefc # the selected GC
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# Use the modules of the compiler
|
|
||||||
|
|
||||||
path: "$nimrod/compiler"
|
|
||||||
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# Pas2nim - Pascal to Nimrod source converter
|
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
import
|
|
||||||
strutils, os, parseopt, llstream, ast, renderer, options, msgs,
|
|
||||||
paslex, pasparse
|
|
||||||
|
|
||||||
const
|
|
||||||
Version = "0.8"
|
|
||||||
Usage = """
|
|
||||||
pas2nim - Pascal to Nimrod source converter
|
|
||||||
(c) 2012 Andreas Rumpf
|
|
||||||
Usage: pas2nim [options] inputfile [options]
|
|
||||||
Options:
|
|
||||||
-o, --out:FILE set output filename
|
|
||||||
--ref convert ^typ to ref typ (default: ptr typ)
|
|
||||||
--boot use special translation rules for the Nimrod compiler
|
|
||||||
-v, --version write pas2nim's version
|
|
||||||
-h, --help show this help
|
|
||||||
"""
|
|
||||||
|
|
||||||
proc main(infile, outfile: string, flags: set[TParserFlag]) =
|
|
||||||
var stream = llStreamOpen(infile, fmRead)
|
|
||||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
|
||||||
var p: TParser
|
|
||||||
openParser(p, infile, stream, flags)
|
|
||||||
var module = parseUnit(p)
|
|
||||||
closeParser(p)
|
|
||||||
renderModule(module, outfile)
|
|
||||||
|
|
||||||
var
|
|
||||||
infile = ""
|
|
||||||
outfile = ""
|
|
||||||
flags: set[TParserFlag] = {}
|
|
||||||
for kind, key, val in getopt():
|
|
||||||
case kind
|
|
||||||
of cmdArgument: infile = key
|
|
||||||
of cmdLongOption, cmdShortOption:
|
|
||||||
case key
|
|
||||||
of "help", "h":
|
|
||||||
stdout.write(Usage)
|
|
||||||
quit(0)
|
|
||||||
of "version", "v":
|
|
||||||
stdout.write(Version & "\n")
|
|
||||||
quit(0)
|
|
||||||
of "o", "out": outfile = val
|
|
||||||
of "ref": incl(flags, pfRefs)
|
|
||||||
of "boot": flags = flags + {pfRefs, pfMoreReplacements, pfImportBlackList}
|
|
||||||
else: stdout.writeln("[Error] unknown option: " & key)
|
|
||||||
of cmdEnd: assert(false)
|
|
||||||
if infile.len == 0:
|
|
||||||
# no filename has been given, so we show the help:
|
|
||||||
stdout.write(Usage)
|
|
||||||
else:
|
|
||||||
if outfile.len == 0:
|
|
||||||
outfile = changeFileExt(infile, "nim")
|
|
||||||
infile = addFileExt(infile, "pas")
|
|
||||||
main(infile, outfile, flags)
|
|
||||||
|
|
@ -1,570 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# Pas2nim - Pascal to Nimrod source converter
|
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
# This module implements a FreePascal scanner. This is an adaption from
|
|
||||||
# the scanner module.
|
|
||||||
|
|
||||||
import
|
|
||||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream
|
|
||||||
|
|
||||||
const
|
|
||||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
|
||||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
|
||||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
|
||||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
|
||||||
OpChars*: TCharSet = {'+', '-', '*', '/', '<', '>', '!', '?', '^', '.', '|',
|
|
||||||
'=', ':', '%', '&', '$', '@', '~', '\x80'..'\xFF'}
|
|
||||||
|
|
||||||
# keywords are sorted!
|
|
||||||
|
|
||||||
type
|
|
||||||
TTokKind* = enum
|
|
||||||
pxInvalid, pxEof,
|
|
||||||
pxAnd, pxArray, pxAs, pxAsm, pxBegin, pxCase, pxClass, pxConst,
|
|
||||||
pxConstructor, pxDestructor, pxDiv, pxDo, pxDownto, pxElse, pxEnd, pxExcept,
|
|
||||||
pxExports, pxFinalization, pxFinally, pxFor, pxFunction, pxGoto, pxIf,
|
|
||||||
pxImplementation, pxIn, pxInherited, pxInitialization, pxInline,
|
|
||||||
pxInterface, pxIs, pxLabel, pxLibrary, pxMod, pxNil, pxNot, pxObject, pxOf,
|
|
||||||
pxOr, pxOut, pxPacked, pxProcedure, pxProgram, pxProperty, pxRaise,
|
|
||||||
pxRecord, pxRepeat, pxResourcestring, pxSet, pxShl, pxShr, pxThen,
|
|
||||||
pxThreadvar, pxTo, pxTry, pxType, pxUnit, pxUntil, pxUses, pxVar, pxWhile,
|
|
||||||
pxWith, pxXor,
|
|
||||||
pxComment, # ordinary comment
|
|
||||||
pxCommand, # {@}
|
|
||||||
pxAmp, # {&}
|
|
||||||
pxPer, # {%}
|
|
||||||
pxStrLit, pxSymbol, # a symbol
|
|
||||||
pxIntLit, pxInt64Lit, # long constant like 0x70fffffff or out of int range
|
|
||||||
pxFloatLit, pxParLe, pxParRi, pxBracketLe, pxBracketRi, pxComma,
|
|
||||||
pxSemiColon, pxColon, # operators
|
|
||||||
pxAsgn, pxEquals, pxDot, pxDotDot, pxHat, pxPlus, pxMinus, pxStar, pxSlash,
|
|
||||||
pxLe, pxLt, pxGe, pxGt, pxNeq, pxAt, pxStarDirLe, pxStarDirRi, pxCurlyDirLe,
|
|
||||||
pxCurlyDirRi
|
|
||||||
TTokKinds* = set[TTokKind]
|
|
||||||
|
|
||||||
const
|
|
||||||
Keywords = ["and", "array", "as", "asm", "begin", "case", "class", "const",
|
|
||||||
"constructor", "destructor", "div", "do", "downto", "else", "end", "except",
|
|
||||||
"exports", "finalization", "finally", "for", "function", "goto", "if",
|
|
||||||
"implementation", "in", "inherited", "initialization", "inline",
|
|
||||||
"interface", "is", "label", "library", "mod", "nil", "not", "object", "of",
|
|
||||||
"or", "out", "packed", "procedure", "program", "property", "raise",
|
|
||||||
"record", "repeat", "resourcestring", "set", "shl", "shr", "then",
|
|
||||||
"threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while",
|
|
||||||
"with", "xor"]
|
|
||||||
|
|
||||||
firstKeyword = pxAnd
|
|
||||||
lastKeyword = pxXor
|
|
||||||
|
|
||||||
type
|
|
||||||
TNumericalBase* = enum base10, base2, base8, base16
|
|
||||||
TToken* = object
|
|
||||||
xkind*: TTokKind # the type of the token
|
|
||||||
ident*: PIdent # the parsed identifier
|
|
||||||
iNumber*: BiggestInt # the parsed integer literal
|
|
||||||
fNumber*: BiggestFloat # the parsed floating point literal
|
|
||||||
base*: TNumericalBase # the numerical base; only valid for int
|
|
||||||
# or float literals
|
|
||||||
literal*: string # the parsed (string) literal
|
|
||||||
|
|
||||||
TLexer* = object of TBaseLexer
|
|
||||||
filename*: string
|
|
||||||
|
|
||||||
|
|
||||||
proc getTok*(L: var TLexer, tok: var TToken)
|
|
||||||
proc printTok*(tok: TToken)
|
|
||||||
proc `$`*(tok: TToken): string
|
|
||||||
# implementation
|
|
||||||
|
|
||||||
var
|
|
||||||
dummyIdent: PIdent
|
|
||||||
gLinesCompiled: int
|
|
||||||
|
|
||||||
proc fillToken(L: var TToken) =
|
|
||||||
L.xkind = pxInvalid
|
|
||||||
L.iNumber = 0
|
|
||||||
L.literal = ""
|
|
||||||
L.fNumber = 0.0
|
|
||||||
L.base = base10
|
|
||||||
L.ident = dummyIdent # this prevents many bugs!
|
|
||||||
|
|
||||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
|
||||||
openBaseLexer(lex, inputstream)
|
|
||||||
lex.filename = filename
|
|
||||||
|
|
||||||
proc closeLexer*(lex: var TLexer) =
|
|
||||||
inc(gLinesCompiled, lex.LineNumber)
|
|
||||||
closeBaseLexer(lex)
|
|
||||||
|
|
||||||
proc getColumn(L: TLexer): int =
|
|
||||||
result = getColNumber(L, L.bufPos)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc tokKindToStr*(k: TTokKind): string =
|
|
||||||
case k
|
|
||||||
of pxEof: result = "[EOF]"
|
|
||||||
of firstKeyword..lastKeyword:
|
|
||||||
result = Keywords[ord(k)-ord(firstKeyword)]
|
|
||||||
of pxInvalid, pxComment, pxStrLit: result = "string literal"
|
|
||||||
of pxCommand: result = "{@"
|
|
||||||
of pxAmp: result = "{&"
|
|
||||||
of pxPer: result = "{%"
|
|
||||||
of pxSymbol: result = "identifier"
|
|
||||||
of pxIntLit, pxInt64Lit: result = "integer literal"
|
|
||||||
of pxFloatLit: result = "floating point literal"
|
|
||||||
of pxParLe: result = "("
|
|
||||||
of pxParRi: result = ")"
|
|
||||||
of pxBracketLe: result = "["
|
|
||||||
of pxBracketRi: result = "]"
|
|
||||||
of pxComma: result = ","
|
|
||||||
of pxSemiColon: result = ";"
|
|
||||||
of pxColon: result = ":"
|
|
||||||
of pxAsgn: result = ":="
|
|
||||||
of pxEquals: result = "="
|
|
||||||
of pxDot: result = "."
|
|
||||||
of pxDotDot: result = ".."
|
|
||||||
of pxHat: result = "^"
|
|
||||||
of pxPlus: result = "+"
|
|
||||||
of pxMinus: result = "-"
|
|
||||||
of pxStar: result = "*"
|
|
||||||
of pxSlash: result = "/"
|
|
||||||
of pxLe: result = "<="
|
|
||||||
of pxLt: result = "<"
|
|
||||||
of pxGe: result = ">="
|
|
||||||
of pxGt: result = ">"
|
|
||||||
of pxNeq: result = "<>"
|
|
||||||
of pxAt: result = "@"
|
|
||||||
of pxStarDirLe: result = "(*$"
|
|
||||||
of pxStarDirRi: result = "*)"
|
|
||||||
of pxCurlyDirLe: result = "{$"
|
|
||||||
of pxCurlyDirRi: result = "}"
|
|
||||||
|
|
||||||
proc `$`(tok: TToken): string =
|
|
||||||
case tok.xkind
|
|
||||||
of pxInvalid, pxComment, pxStrLit: result = tok.literal
|
|
||||||
of pxSymbol: result = tok.ident.s
|
|
||||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
|
||||||
of pxFloatLit: result = $tok.fNumber
|
|
||||||
else: result = tokKindToStr(tok.xkind)
|
|
||||||
|
|
||||||
proc printTok(tok: TToken) =
|
|
||||||
writeln(stdout, $tok)
|
|
||||||
|
|
||||||
proc setKeyword(L: var TLexer, tok: var TToken) =
|
|
||||||
var x = binaryStrSearch(keywords, toLower(tok.ident.s))
|
|
||||||
if x < 0: tok.xkind = pxSymbol
|
|
||||||
else: tok.xKind = TTokKind(x + ord(firstKeyword))
|
|
||||||
|
|
||||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
|
||||||
# matches ([chars]_)*
|
|
||||||
var pos = L.bufpos # use registers for pos, buf
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
if buf[pos] in chars:
|
|
||||||
add(tok.literal, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
if buf[pos] == '_':
|
|
||||||
add(tok.literal, '_')
|
|
||||||
inc(pos)
|
|
||||||
L.bufPos = pos
|
|
||||||
|
|
||||||
proc isFloatLiteral(s: string): bool =
|
|
||||||
for i in countup(0, len(s)-1):
|
|
||||||
if s[i] in {'.', 'e', 'E'}:
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 1 # skip %
|
|
||||||
if not (L.buf[pos] in {'0'..'1'}):
|
|
||||||
# BUGFIX for %date%
|
|
||||||
tok.xkind = pxInvalid
|
|
||||||
add(tok.literal, '%')
|
|
||||||
inc(L.bufpos)
|
|
||||||
return
|
|
||||||
tok.base = base2
|
|
||||||
var xi: BiggestInt = 0
|
|
||||||
var bits = 0
|
|
||||||
while true:
|
|
||||||
case L.buf[pos]
|
|
||||||
of 'A'..'Z', 'a'..'z', '2'..'9', '.':
|
|
||||||
lexMessage(L, errInvalidNumber)
|
|
||||||
inc(pos)
|
|
||||||
of '_':
|
|
||||||
inc(pos)
|
|
||||||
of '0', '1':
|
|
||||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
inc(bits)
|
|
||||||
else: break
|
|
||||||
tok.iNumber = xi
|
|
||||||
if (bits > 32): tok.xkind = pxInt64Lit
|
|
||||||
else: tok.xkind = pxIntLit
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos + 1 # skip $
|
|
||||||
tok.base = base16
|
|
||||||
var xi: BiggestInt = 0
|
|
||||||
var bits = 0
|
|
||||||
while true:
|
|
||||||
case L.buf[pos]
|
|
||||||
of 'G'..'Z', 'g'..'z', '.':
|
|
||||||
lexMessage(L, errInvalidNumber)
|
|
||||||
inc(pos)
|
|
||||||
of '_': inc(pos)
|
|
||||||
of '0'..'9':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
of 'a'..'f':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
of 'A'..'F':
|
|
||||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
|
||||||
inc(pos)
|
|
||||||
inc(bits, 4)
|
|
||||||
else: break
|
|
||||||
tok.iNumber = xi
|
|
||||||
if (bits > 32):
|
|
||||||
tok.xkind = pxInt64Lit
|
|
||||||
else:
|
|
||||||
tok.xkind = pxIntLit
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getNumber10(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.literal, '.')
|
|
||||||
inc(L.bufpos)
|
|
||||||
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
|
|
||||||
try:
|
|
||||||
if isFloatLiteral(tok.literal):
|
|
||||||
tok.fnumber = parseFloat(tok.literal)
|
|
||||||
tok.xkind = pxFloatLit
|
|
||||||
else:
|
|
||||||
tok.iNumber = parseInt(tok.literal)
|
|
||||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
|
||||||
tok.xkind = pxInt64Lit
|
|
||||||
else:
|
|
||||||
tok.xkind = pxIntLit
|
|
||||||
except EInvalidValue:
|
|
||||||
lexMessage(L, errInvalidNumber, tok.literal)
|
|
||||||
except EOverflow:
|
|
||||||
lexMessage(L, errNumberOutOfRange, tok.literal)
|
|
||||||
|
|
||||||
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)
|
|
||||||
else: result = pos
|
|
||||||
|
|
||||||
proc getString(L: var TLexer, tok: var TToken) =
|
|
||||||
var xi: int
|
|
||||||
var pos = L.bufPos
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
if buf[pos] == '\'':
|
|
||||||
inc(pos)
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of CR, LF, nimlexbase.EndOfFile:
|
|
||||||
lexMessage(L, errClosingQuoteExpected)
|
|
||||||
break
|
|
||||||
of '\'':
|
|
||||||
inc(pos)
|
|
||||||
if buf[pos] == '\'':
|
|
||||||
inc(pos)
|
|
||||||
add(tok.literal, '\'')
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
add(tok.literal, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
elif buf[pos] == '#':
|
|
||||||
inc(pos)
|
|
||||||
xi = 0
|
|
||||||
case buf[pos]
|
|
||||||
of '$':
|
|
||||||
inc(pos)
|
|
||||||
xi = 0
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of '0'..'9': xi = (xi shl 4) or (ord(buf[pos]) - ord('0'))
|
|
||||||
of 'a'..'f': xi = (xi shl 4) or (ord(buf[pos]) - ord('a') + 10)
|
|
||||||
of 'A'..'F': xi = (xi shl 4) or (ord(buf[pos]) - ord('A') + 10)
|
|
||||||
else: break
|
|
||||||
inc(pos)
|
|
||||||
of '0'..'9':
|
|
||||||
xi = 0
|
|
||||||
while buf[pos] in {'0'..'9'}:
|
|
||||||
xi = (xi * 10) + (ord(buf[pos]) - ord('0'))
|
|
||||||
inc(pos)
|
|
||||||
else: lexMessage(L, errInvalidCharacterConstant)
|
|
||||||
if (xi <= 255): add(tok.literal, chr(xi))
|
|
||||||
else: lexMessage(L, errInvalidCharacterConstant)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
tok.xkind = pxStrLit
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
|
||||||
var h: THash = 0
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
var c = buf[pos]
|
|
||||||
case c
|
|
||||||
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
|
|
||||||
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 +% h shl 10
|
|
||||||
h = h xor (h shr 6)
|
|
||||||
of '_': discard
|
|
||||||
else: break
|
|
||||||
inc(pos)
|
|
||||||
h = h +% h shl 3
|
|
||||||
h = h xor (h shr 11)
|
|
||||||
h = h +% h shl 15
|
|
||||||
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
|
||||||
L.bufpos = pos
|
|
||||||
setKeyword(L, tok)
|
|
||||||
|
|
||||||
proc scanLineComment(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
# a comment ends if the next line does not start with the // on the same
|
|
||||||
# column after only whitespace
|
|
||||||
tok.xkind = pxComment
|
|
||||||
var col = getColNumber(L, pos)
|
|
||||||
while true:
|
|
||||||
inc(pos, 2) # skip //
|
|
||||||
add(tok.literal, '#')
|
|
||||||
while not (buf[pos] in {CR, LF, nimlexbase.EndOfFile}):
|
|
||||||
add(tok.literal, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
var indent = 0
|
|
||||||
while buf[pos] == ' ':
|
|
||||||
inc(pos)
|
|
||||||
inc(indent)
|
|
||||||
if (col == indent) and (buf[pos] == '/') and (buf[pos + 1] == '/'):
|
|
||||||
tok.literal = tok.literal & "\n"
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc scanCurlyComment(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
tok.literal = "#"
|
|
||||||
tok.xkind = pxComment
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of CR, LF:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
add(tok.literal, "\n#")
|
|
||||||
of '}':
|
|
||||||
inc(pos)
|
|
||||||
break
|
|
||||||
of nimlexbase.EndOfFile: lexMessage(L, errTokenExpected, "}")
|
|
||||||
else:
|
|
||||||
add(tok.literal, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc scanStarComment(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
tok.literal = "#"
|
|
||||||
tok.xkind = pxComment
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of CR, LF:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
add(tok.literal, "\n#")
|
|
||||||
of '*':
|
|
||||||
inc(pos)
|
|
||||||
if buf[pos] == ')':
|
|
||||||
inc(pos)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
add(tok.literal, '*')
|
|
||||||
of nimlexbase.EndOfFile:
|
|
||||||
lexMessage(L, errTokenExpected, "*)")
|
|
||||||
else:
|
|
||||||
add(tok.literal, buf[pos])
|
|
||||||
inc(pos)
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc skip(L: var TLexer, tok: var TToken) =
|
|
||||||
var pos = L.bufpos
|
|
||||||
var buf = L.buf
|
|
||||||
while true:
|
|
||||||
case buf[pos]
|
|
||||||
of ' ', Tabulator:
|
|
||||||
inc(pos) # newline is special:
|
|
||||||
of CR, LF:
|
|
||||||
pos = handleCRLF(L, pos)
|
|
||||||
buf = L.buf
|
|
||||||
else:
|
|
||||||
break # EndOfFile also leaves the loop
|
|
||||||
L.bufpos = pos
|
|
||||||
|
|
||||||
proc getTok(L: var TLexer, tok: var TToken) =
|
|
||||||
tok.xkind = pxInvalid
|
|
||||||
fillToken(tok)
|
|
||||||
skip(L, tok)
|
|
||||||
var c = L.buf[L.bufpos]
|
|
||||||
if c in SymStartChars:
|
|
||||||
getSymbol(L, tok)
|
|
||||||
elif c in {'0'..'9'}:
|
|
||||||
getNumber10(L, tok)
|
|
||||||
else:
|
|
||||||
case c
|
|
||||||
of ';':
|
|
||||||
tok.xkind = pxSemicolon
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '/':
|
|
||||||
if L.buf[L.bufpos + 1] == '/':
|
|
||||||
scanLineComment(L, tok)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxSlash
|
|
||||||
inc(L.bufpos)
|
|
||||||
of ',':
|
|
||||||
tok.xkind = pxComma
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '(':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if (L.buf[L.bufPos] == '*'):
|
|
||||||
if (L.buf[L.bufPos + 1] == '$'):
|
|
||||||
inc(L.bufpos, 2)
|
|
||||||
skip(L, tok)
|
|
||||||
getSymbol(L, tok)
|
|
||||||
tok.xkind = pxStarDirLe
|
|
||||||
else:
|
|
||||||
inc(L.bufpos)
|
|
||||||
scanStarComment(L, tok)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxParLe
|
|
||||||
of '*':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == ')':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxStarDirRi
|
|
||||||
else:
|
|
||||||
tok.xkind = pxStar
|
|
||||||
of ')':
|
|
||||||
tok.xkind = pxParRi
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '[':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxBracketLe
|
|
||||||
of ']':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxBracketRi
|
|
||||||
of '.':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '.':
|
|
||||||
tok.xkind = pxDotDot
|
|
||||||
inc(L.bufpos)
|
|
||||||
else:
|
|
||||||
tok.xkind = pxDot
|
|
||||||
of '{':
|
|
||||||
inc(L.bufpos)
|
|
||||||
case L.buf[L.bufpos]
|
|
||||||
of '$':
|
|
||||||
inc(L.bufpos)
|
|
||||||
skip(L, tok)
|
|
||||||
getSymbol(L, tok)
|
|
||||||
tok.xkind = pxCurlyDirLe
|
|
||||||
of '&':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxAmp
|
|
||||||
of '%':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxPer
|
|
||||||
of '@':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxCommand
|
|
||||||
else: scanCurlyComment(L, tok)
|
|
||||||
of '+':
|
|
||||||
tok.xkind = pxPlus
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '-':
|
|
||||||
tok.xkind = pxMinus
|
|
||||||
inc(L.bufpos)
|
|
||||||
of ':':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxAsgn
|
|
||||||
else:
|
|
||||||
tok.xkind = pxColon
|
|
||||||
of '<':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '>':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxNeq
|
|
||||||
elif L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxLe
|
|
||||||
else:
|
|
||||||
tok.xkind = pxLt
|
|
||||||
of '>':
|
|
||||||
inc(L.bufpos)
|
|
||||||
if L.buf[L.bufpos] == '=':
|
|
||||||
inc(L.bufpos)
|
|
||||||
tok.xkind = pxGe
|
|
||||||
else:
|
|
||||||
tok.xkind = pxGt
|
|
||||||
of '=':
|
|
||||||
tok.xkind = pxEquals
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '@':
|
|
||||||
tok.xkind = pxAt
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '^':
|
|
||||||
tok.xkind = pxHat
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '}':
|
|
||||||
tok.xkind = pxCurlyDirRi
|
|
||||||
inc(L.bufpos)
|
|
||||||
of '\'', '#':
|
|
||||||
getString(L, tok)
|
|
||||||
of '$':
|
|
||||||
getNumber16(L, tok)
|
|
||||||
of '%':
|
|
||||||
getNumber2(L, tok)
|
|
||||||
of nimlexbase.EndOfFile:
|
|
||||||
tok.xkind = pxEof
|
|
||||||
else:
|
|
||||||
tok.literal = c & ""
|
|
||||||
tok.xkind = pxInvalid
|
|
||||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
|
||||||
inc(L.bufpos)
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -24,7 +24,8 @@ const
|
||||||
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||||
wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe}
|
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
|
||||||
|
wOverride}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas
|
methodPragmas* = procPragmas
|
||||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
|
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
|
||||||
|
|
@ -35,8 +36,8 @@ const
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||||
wTags, wUses, wOperator, wGcSafe}
|
wTags, wLocks, wGcSafe}
|
||||||
exprPragmas* = {wLine}
|
exprPragmas* = {wLine, wLocks}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||||
|
|
@ -44,27 +45,27 @@ const
|
||||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||||
wInjectStmt}
|
wInjectStmt, wDeprecated}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
wRaises, wUses, wTags, wGcSafe}
|
wRaises, wLocks, wTags, wGcSafe}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||||
wBorrow, wGcSafe}
|
wBorrow, wGcSafe}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportCpp, wImportObjC, wError}
|
wImportCpp, wImportObjC, wError, wGuard}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||||
wGensym, wInject, wCodegenDecl}
|
wGensym, wInject, wCodegenDecl, wGuard}
|
||||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||||
letPragmas* = varPragmas
|
letPragmas* = varPragmas
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||||
wThread, wRaises, wUses, wTags, wGcSafe}
|
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||||
|
|
||||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||||
|
|
@ -127,12 +128,16 @@ proc processImportCpp(s: PSym, extname: string) =
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfInfixCall)
|
incl(s.flags, sfInfixCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
let m = s.getModule()
|
||||||
|
incl(m.flags, sfCompileToCpp)
|
||||||
|
|
||||||
proc processImportObjC(s: PSym, extname: string) =
|
proc processImportObjC(s: PSym, extname: string) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfNamedParamCall)
|
incl(s.flags, sfNamedParamCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
let m = s.getModule()
|
||||||
|
incl(m.flags, sfCompileToObjC)
|
||||||
|
|
||||||
proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
||||||
result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
||||||
|
|
@ -513,27 +518,6 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
invalidPragma(n)
|
invalidPragma(n)
|
||||||
|
|
||||||
proc pragmaUses(c: PContext, n: PNode) =
|
|
||||||
proc processExc(c: PContext, x: PNode): PNode =
|
|
||||||
if x.kind in {nkAccQuoted, nkIdent, nkSym,
|
|
||||||
nkOpenSymChoice, nkClosedSymChoice}:
|
|
||||||
if considerQuotedIdent(x).s == "*":
|
|
||||||
return newSymNode(ast.anyGlobal)
|
|
||||||
result = c.semExpr(c, x)
|
|
||||||
if result.kind != nkSym or sfGlobal notin result.sym.flags:
|
|
||||||
localError(x.info, "'$1' is not a global variable" % result.renderTree)
|
|
||||||
result = newSymNode(ast.anyGlobal)
|
|
||||||
|
|
||||||
if n.kind == nkExprColonExpr:
|
|
||||||
let it = n.sons[1]
|
|
||||||
if it.kind notin {nkCurly, nkBracket}:
|
|
||||||
n.sons[1] = processExc(c, it)
|
|
||||||
else:
|
|
||||||
for i in 0 .. <it.len:
|
|
||||||
it.sons[i] = processExc(c, it.sons[i])
|
|
||||||
else:
|
|
||||||
invalidPragma(n)
|
|
||||||
|
|
||||||
proc typeBorrow(sym: PSym, n: PNode) =
|
proc typeBorrow(sym: PSym, n: PNode) =
|
||||||
if n.kind == nkExprColonExpr:
|
if n.kind == nkExprColonExpr:
|
||||||
let it = n.sons[1]
|
let it = n.sons[1]
|
||||||
|
|
@ -541,6 +525,45 @@ proc typeBorrow(sym: PSym, n: PNode) =
|
||||||
localError(n.info, "a type can only borrow `.` for now")
|
localError(n.info, "a type can only borrow `.` for now")
|
||||||
incl(sym.typ.flags, tfBorrowDot)
|
incl(sym.typ.flags, tfBorrowDot)
|
||||||
|
|
||||||
|
proc markCompilerProc(s: PSym) =
|
||||||
|
makeExternExport(s, "$1", s.info)
|
||||||
|
incl(s.flags, sfCompilerProc)
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
registerCompilerProc(s)
|
||||||
|
|
||||||
|
proc deprecatedStmt(c: PContext; pragma: PNode) =
|
||||||
|
let pragma = pragma[1]
|
||||||
|
if pragma.kind != nkBracket:
|
||||||
|
localError(pragma.info, "list of key:value pairs expected"); return
|
||||||
|
for n in pragma:
|
||||||
|
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
|
||||||
|
let dest = qualifiedLookUp(c, n[1])
|
||||||
|
let src = considerQuotedIdent(n[0])
|
||||||
|
let alias = newSym(skAlias, src, dest, n[0].info)
|
||||||
|
incl(alias.flags, sfExported)
|
||||||
|
if sfCompilerProc in dest.flags: markCompilerProc(alias)
|
||||||
|
addInterfaceDecl(c, alias)
|
||||||
|
else:
|
||||||
|
localError(n.info, "key:value pair expected")
|
||||||
|
|
||||||
|
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||||
|
if it.kind != nkExprColonExpr:
|
||||||
|
invalidPragma(it); return
|
||||||
|
let n = it[1]
|
||||||
|
if n.kind == nkSym:
|
||||||
|
result = n.sym
|
||||||
|
elif kind == skField:
|
||||||
|
# First check if the guard is a global variable:
|
||||||
|
result = qualifiedLookUp(c, n, {})
|
||||||
|
if result.isNil or result.kind notin {skLet, skVar} or
|
||||||
|
sfGlobal notin result.flags:
|
||||||
|
# We return a dummy symbol; later passes over the type will repair it.
|
||||||
|
# Generic instantiation needs to know about this too. But we're lazy
|
||||||
|
# and perform the lookup on demand instead.
|
||||||
|
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
|
||||||
|
else:
|
||||||
|
result = qualifiedLookUp(c, n)
|
||||||
|
|
||||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
validPragmas: TSpecialWords): bool =
|
validPragmas: TSpecialWords): bool =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
|
|
@ -577,10 +600,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
of wAlign:
|
of wAlign:
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
var align = expectIntLit(c, it)
|
var align = expectIntLit(c, it)
|
||||||
if not isPowerOfTwo(align) and align != 0:
|
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
|
||||||
localError(it.info, errPowerOfTwoExpected)
|
localError(it.info, errPowerOfTwoExpected)
|
||||||
else:
|
else:
|
||||||
sym.typ.align = align
|
sym.typ.align = align.int16
|
||||||
of wSize:
|
of wSize:
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
var size = expectIntLit(c, it)
|
var size = expectIntLit(c, it)
|
||||||
|
|
@ -628,10 +651,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
# implies nodecl, because otherwise header would not make sense
|
# implies nodecl, because otherwise header would not make sense
|
||||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||||
of wDestructor:
|
of wDestructor:
|
||||||
if sym.typ.sons.len == 2:
|
sym.flags.incl sfOverriden
|
||||||
sym.flags.incl sfDestructor
|
if sym.name.s.normalize != "destroy":
|
||||||
else:
|
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
|
||||||
invalidPragma(it)
|
of wOverride:
|
||||||
|
sym.flags.incl sfOverriden
|
||||||
of wNosideeffect:
|
of wNosideeffect:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
incl(sym.flags, sfNoSideEffect)
|
incl(sym.flags, sfNoSideEffect)
|
||||||
|
|
@ -646,17 +670,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
processDynLib(c, it, sym)
|
processDynLib(c, it, sym)
|
||||||
of wCompilerproc:
|
of wCompilerproc:
|
||||||
noVal(it) # compilerproc may not get a string!
|
noVal(it) # compilerproc may not get a string!
|
||||||
if sfFromGeneric notin sym.flags:
|
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||||
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)
|
noVal(it)
|
||||||
incl(sym.flags, sfProcvar)
|
incl(sym.flags, sfProcvar)
|
||||||
of wDeprecated:
|
of wDeprecated:
|
||||||
noVal(it)
|
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||||
if sym != nil: incl(sym.flags, sfDeprecated)
|
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||||
else: incl(c.module.flags, sfDeprecated)
|
else: incl(c.module.flags, sfDeprecated)
|
||||||
of wVarargs:
|
of wVarargs:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
|
|
@ -787,10 +807,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
if sym == nil: invalidPragma(it)
|
if sym == nil: invalidPragma(it)
|
||||||
of wLine: pragmaLine(c, it)
|
of wLine: pragmaLine(c, it)
|
||||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||||
of wUses: pragmaUses(c, it)
|
of wGuard:
|
||||||
of wOperator:
|
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||||
if sym == nil: invalidPragma(it)
|
invalidPragma(it)
|
||||||
else: sym.position = expectIntLit(c, it)
|
else:
|
||||||
|
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||||
of wInjectStmt:
|
of wInjectStmt:
|
||||||
if it.kind != nkExprColonExpr:
|
if it.kind != nkExprColonExpr:
|
||||||
localError(it.info, errExprExpected)
|
localError(it.info, errExprExpected)
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,15 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
var it: TIdentIter
|
var it: TIdentIter
|
||||||
result = initIdentIter(it, scope.symbols, fn.name)
|
result = initIdentIter(it, scope.symbols, fn.name)
|
||||||
while result != nil:
|
while result != nil:
|
||||||
if result.kind in skProcKinds and
|
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
||||||
sameType(result.typ, fn.typ, flags): return
|
case equalParams(result.typ.n, fn.typ.n)
|
||||||
|
of paramsEqual:
|
||||||
|
return
|
||||||
|
of paramsIncompatible:
|
||||||
|
localError(fn.info, errNotOverloadable, fn.name.s)
|
||||||
|
return
|
||||||
|
of paramsNotEqual:
|
||||||
|
discard
|
||||||
|
|
||||||
result = nextIdentIter(it, scope.symbols)
|
result = nextIdentIter(it, scope.symbols)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -925,7 +925,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
|
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkLambda:
|
of nkLambda:
|
||||||
putWithSpace(g, tkLambda, "proc")
|
putWithSpace(g, tkProc, "proc")
|
||||||
gsub(g, n.sons[paramsPos])
|
gsub(g, n.sons[paramsPos])
|
||||||
gsub(g, n.sons[pragmasPos])
|
gsub(g, n.sons[pragmasPos])
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import
|
||||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||||
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
|
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
|
||||||
semparallel
|
semparallel, lowerings
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||||
if c.inCompilesContext > 0:
|
if c.inCompilesContext > 0:
|
||||||
# fail fast:
|
# fail fast:
|
||||||
globalError(n.info, errTypeMismatch, "")
|
globalError(n.info, errTypeMismatch, "")
|
||||||
|
if errors.len == 0:
|
||||||
|
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||||
var result = msgKindToString(errTypeMismatch)
|
var result = msgKindToString(errTypeMismatch)
|
||||||
add(result, describeArgs(c, n, 1))
|
add(result, describeArgs(c, n, 1))
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
|
|
|
||||||
|
|
@ -125,8 +125,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||||
# The destructor is either user-defined or automatically
|
# The destructor is either user-defined or automatically
|
||||||
# generated by the compiler in a member-wise fashion.
|
# generated by the compiler in a member-wise fashion.
|
||||||
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
|
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
|
||||||
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
|
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
|
||||||
else: t
|
|
||||||
|
|
||||||
if typeHoldingUserDefinition.destructor != nil:
|
if typeHoldingUserDefinition.destructor != nil:
|
||||||
# XXX: This is not entirely correct for recursive types, but we need
|
# XXX: This is not entirely correct for recursive types, but we need
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
||||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
tyTuple, tySet, tyUInt..tyUInt64:
|
tyTuple, tySet, tyUInt..tyUInt64:
|
||||||
result = inlineConst(n, s)
|
if s.magic == mNone: result = inlineConst(n, s)
|
||||||
|
else: result = newSymNode(s, n.info)
|
||||||
of tyArrayConstr, tySequence:
|
of tyArrayConstr, tySequence:
|
||||||
# Consider::
|
# Consider::
|
||||||
# const x = []
|
# const x = []
|
||||||
|
|
@ -184,6 +185,8 @@ proc isCastable(dst, src: PType): bool =
|
||||||
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
|
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
|
||||||
# tySequence, tyPointer, tyNil, tyOpenArray,
|
# tySequence, tyPointer, tyNil, tyOpenArray,
|
||||||
# tyProc, tySet, tyEnum, tyBool, tyChar}
|
# tyProc, tySet, tyEnum, tyBool, tyChar}
|
||||||
|
if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
|
||||||
|
return false
|
||||||
var dstSize, srcSize: BiggestInt
|
var dstSize, srcSize: BiggestInt
|
||||||
|
|
||||||
dstSize = computeSize(dst)
|
dstSize = computeSize(dst)
|
||||||
|
|
@ -198,6 +201,8 @@ proc isCastable(dst, src: PType): bool =
|
||||||
result = (dstSize >= srcSize) or
|
result = (dstSize >= srcSize) or
|
||||||
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
||||||
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
|
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
|
||||||
|
if result and src.kind == tyNil:
|
||||||
|
result = dst.size <= platform.ptrSize
|
||||||
|
|
||||||
proc isSymChoice(n: PNode): bool {.inline.} =
|
proc isSymChoice(n: PNode): bool {.inline.} =
|
||||||
result = n.kind in nkSymChoices
|
result = n.kind in nkSymChoices
|
||||||
|
|
@ -591,7 +596,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||||
const
|
const
|
||||||
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
|
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
|
||||||
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
|
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
|
||||||
mAppendSeqElem, mNewSeq, mReset, mShallowCopy}
|
mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
|
||||||
|
|
||||||
# get the real type of the callee
|
# get the real type of the callee
|
||||||
# it may be a proc var with a generic alias type, so we skip over them
|
# it may be a proc var with a generic alias type, so we skip over them
|
||||||
|
|
@ -657,7 +662,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
# optimization pass: not necessary for correctness of the semantic pass
|
# optimization pass: not necessary for correctness of the semantic pass
|
||||||
if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
|
if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
|
||||||
{sfForward, sfImportc} * callee.flags == {}:
|
{sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
|
||||||
if sfCompileTime notin callee.flags and
|
if sfCompileTime notin callee.flags and
|
||||||
optImplicitStatic notin gOptions: return
|
optImplicitStatic notin gOptions: return
|
||||||
|
|
||||||
|
|
@ -1369,19 +1374,18 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
|
||||||
if onlyCurrentScope: return
|
if onlyCurrentScope: return
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
|
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
|
||||||
if (m != nil) and (m.kind == skModule):
|
if m != nil and m.kind == skModule:
|
||||||
if (n.sons[1].kind == nkIdent):
|
let ident = considerQuotedIdent(n[1])
|
||||||
var ident = n.sons[1].ident
|
|
||||||
if m == c.module:
|
if m == c.module:
|
||||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||||
else:
|
else:
|
||||||
result = strTableGet(m.tab, ident)
|
result = strTableGet(m.tab, ident)
|
||||||
else:
|
|
||||||
localError(n.sons[1].info, errIdentifierExpected, "")
|
|
||||||
of nkAccQuoted:
|
of nkAccQuoted:
|
||||||
result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
|
result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
|
of nkOpenSymChoice, nkClosedSymChoice:
|
||||||
|
result = n.sons[0].sym
|
||||||
else:
|
else:
|
||||||
localError(n.info, errIdentifierExpected, renderTree(n))
|
localError(n.info, errIdentifierExpected, renderTree(n))
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -1390,10 +1394,16 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
# we replace this node by a 'true' or 'false' node:
|
# we replace this node by a 'true' or 'false' node:
|
||||||
result = newIntNode(nkIntLit, 0)
|
result = newIntNode(nkIntLit, 0)
|
||||||
if lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
|
if not onlyCurrentScope and considerQuotedIdent(n[0]).s == "defined":
|
||||||
|
if n.sons[1].kind != nkIdent:
|
||||||
|
localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
|
||||||
|
elif condsyms.isDefined(n.sons[1].ident):
|
||||||
result.intVal = 1
|
result.intVal = 1
|
||||||
elif not onlyCurrentScope and (n.sons[1].kind == nkIdent) and
|
elif not condsyms.isDeclared(n.sons[1].ident):
|
||||||
condsyms.isDefined(n.sons[1].ident):
|
message(n.info, warnUser,
|
||||||
|
"undeclared conditional symbol; use --symbol to declare it: " &
|
||||||
|
n[1].ident.s)
|
||||||
|
elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
|
||||||
result.intVal = 1
|
result.intVal = 1
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
result.typ = getSysType(tyBool)
|
result.typ = getSysType(tyBool)
|
||||||
|
|
@ -1604,6 +1614,11 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
|
||||||
initIdTable(bindings)
|
initIdTable(bindings)
|
||||||
bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
|
bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
|
||||||
result = c.semGenerateInstance(c, sym, bindings, info)
|
result = c.semGenerateInstance(c, sym, bindings, info)
|
||||||
|
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
|
||||||
|
# codegen would fail:
|
||||||
|
if sfCompilerProc in result.flags:
|
||||||
|
result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
|
||||||
|
result.loc.r = nil
|
||||||
|
|
||||||
proc setMs(n: PNode, s: PSym): PNode =
|
proc setMs(n: PNode, s: PSym): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -1642,10 +1657,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
result = setMs(n, s)
|
result = setMs(n, s)
|
||||||
result.sons[1] = semExpr(c, n.sons[1])
|
result.sons[1] = semExpr(c, n.sons[1])
|
||||||
if not result[1].typ.isEmptyType:
|
if not result[1].typ.isEmptyType:
|
||||||
if c.inParallelStmt > 0:
|
if spawnResult(result[1].typ, c.inParallelStmt > 0) == srFlowVar:
|
||||||
result.typ = result[1].typ
|
|
||||||
else:
|
|
||||||
result.typ = createFlowVar(c, result[1].typ, n.info)
|
result.typ = createFlowVar(c, result[1].typ, n.info)
|
||||||
|
else:
|
||||||
|
result.typ = result[1].typ
|
||||||
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
||||||
else: result = semDirectOp(c, n, flags)
|
else: result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
|
@ -1758,7 +1773,8 @@ proc checkPar(n: PNode): TParKind =
|
||||||
if length == 0:
|
if length == 0:
|
||||||
result = paTuplePositions # ()
|
result = paTuplePositions # ()
|
||||||
elif length == 1:
|
elif length == 1:
|
||||||
result = paSingle # (expr)
|
if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
|
||||||
|
else: result = paSingle # (expr)
|
||||||
else:
|
else:
|
||||||
if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
|
if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
|
||||||
else: result = paTuplePositions
|
else: result = paTuplePositions
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ proc semGenericStmtScope(c: PContext, n: PNode,
|
||||||
template macroToExpand(s: expr): expr =
|
template macroToExpand(s: expr): expr =
|
||||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
||||||
|
|
||||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
|
ctx: var TIntSet): PNode =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skUnknown:
|
of skUnknown:
|
||||||
|
|
@ -48,11 +49,13 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
let n = fixImmediateParams(n)
|
let n = fixImmediateParams(n)
|
||||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||||
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||||
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
|
|
@ -80,7 +83,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
elif s.name.id in ctx:
|
elif s.name.id in ctx:
|
||||||
result = symChoice(c, n, s, scForceOpen)
|
result = symChoice(c, n, s, scForceOpen)
|
||||||
else:
|
else:
|
||||||
result = semGenericStmtSymbol(c, n, s)
|
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||||
# else: leave as nkIdent
|
# else: leave as nkIdent
|
||||||
|
|
||||||
proc newDot(n, b: PNode): PNode =
|
proc newDot(n, b: PNode): PNode =
|
||||||
|
|
@ -95,8 +98,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, luf)
|
var s = qualifiedLookUp(c, n, luf)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
result = semGenericStmtSymbol(c, n, s)
|
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||||
else:
|
else:
|
||||||
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
||||||
result = n
|
result = n
|
||||||
let n = n[1]
|
let n = n[1]
|
||||||
let ident = considerQuotedIdent(n)
|
let ident = considerQuotedIdent(n)
|
||||||
|
|
@ -107,7 +111,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
elif s.name.id in ctx:
|
elif s.name.id in ctx:
|
||||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||||
else:
|
else:
|
||||||
let sym = semGenericStmtSymbol(c, n, s)
|
let sym = semGenericStmtSymbol(c, n, s, ctx)
|
||||||
if sym.kind == nkSym:
|
if sym.kind == nkSym:
|
||||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||||
else:
|
else:
|
||||||
|
|
@ -158,6 +162,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||||
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -165,6 +170,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
let n = fixImmediateParams(n)
|
let n = fixImmediateParams(n)
|
||||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||||
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||||
t = errorType(c)
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericParam:
|
elif t.kind == tyGenericParam:
|
||||||
internalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||||
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericInvokation:
|
elif t.kind == tyGenericInvokation:
|
||||||
#t = instGenericContainer(c, a, t)
|
#t = instGenericContainer(c, a, t)
|
||||||
t = generateTypeInstance(c, pt, a, t)
|
t = generateTypeInstance(c, pt, a, t)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
result.typ = getSysType(tyString)
|
result.typ = getSysType(tyString)
|
||||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||||
of mOrd: result = semOrd(c, n)
|
of mOrd: result = semOrd(c, n)
|
||||||
of mHigh: result = semLowHigh(c, n, mHigh)
|
of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||||
of mNBindSym: result = semBindSym(c, n)
|
of mNBindSym: result = semBindSym(c, n)
|
||||||
of mLocals: result = semLocals(c, n)
|
of mLocals: result = semLocals(c, n)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
|
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
|
||||||
renderer
|
renderer, types
|
||||||
from trees import getMagic
|
from trees import getMagic
|
||||||
from strutils import `%`
|
from strutils import `%`
|
||||||
|
|
||||||
|
|
@ -406,12 +406,17 @@ proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
result.add n
|
result.add n
|
||||||
|
let t = b[1][0].typ.sons[0]
|
||||||
|
if spawnResult(t, true) == srByVar:
|
||||||
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
|
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
|
||||||
it.sons[it.len-1] = emptyNode
|
it.sons[it.len-1] = emptyNode
|
||||||
|
else:
|
||||||
|
it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
|
||||||
if result.isNil: result = n
|
if result.isNil: result = n
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
let b = n[1]
|
let b = n[1]
|
||||||
if getMagic(b) == mSpawn:
|
if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
|
||||||
|
spawnResult(t, true) == srByVar):
|
||||||
let m = transformSlices(b)
|
let m = transformSlices(b)
|
||||||
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
|
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
|
||||||
result = transformSpawnSons(owner, n, barrier)
|
result = transformSpawnSons(owner, n, barrier)
|
||||||
|
|
@ -462,4 +467,3 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
|
||||||
result.add callCodeGenProc("openBarrier", barrier)
|
result.add callCodeGenProc("openBarrier", barrier)
|
||||||
result.add transformSpawn(owner, body, barrier)
|
result.add transformSpawn(owner, body, barrier)
|
||||||
result.add callCodeGenProc("closeBarrier", barrier)
|
result.add callCodeGenProc("closeBarrier", barrier)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ proc useVar(a: PEffects, n: PNode) =
|
||||||
a.addUse(copyNode(n))
|
a.addUse(copyNode(n))
|
||||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||||
tfGcSafe notin s.typ.flags:
|
tfGcSafe notin s.typ.flags:
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
a.gcUnsafe = true
|
a.gcUnsafe = true
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -315,7 +315,6 @@ proc documentRaises*(n: PNode) =
|
||||||
if n.sons[namePos].kind != nkSym: return
|
if n.sons[namePos].kind != nkSym: return
|
||||||
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
||||||
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
||||||
documentEffect(n, n.sons[pragmasPos], wUses, usesEffects)
|
|
||||||
|
|
||||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||||
|
|
||||||
|
|
@ -332,13 +331,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||||
mergeTags(tracked, tagSpec, n)
|
mergeTags(tracked, tagSpec, n)
|
||||||
|
|
||||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
|
|
||||||
when trackGlobals:
|
|
||||||
let usesSpec = effectSpec(pragma, wUses)
|
|
||||||
mergeUses(tracked, usesSpec, n)
|
|
||||||
|
|
||||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
let n = n.skipConv
|
let n = n.skipConv
|
||||||
if paramType != nil and tfNotNil in paramType.flags and
|
if paramType != nil and tfNotNil in paramType.flags and
|
||||||
|
|
@ -358,7 +353,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
of impYes: discard
|
of impYes: discard
|
||||||
|
|
||||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
let op = n.typ
|
let op = skipConvAndClosure(n).typ
|
||||||
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
|
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]
|
var effectList = op.n.sons[0]
|
||||||
|
|
@ -367,21 +362,24 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
propagateEffects(tracked, n, s.sym)
|
propagateEffects(tracked, n, s.sym)
|
||||||
elif effectList.len == 0:
|
elif effectList.len == 0:
|
||||||
if isForwardedProc(n):
|
if isForwardedProc(n):
|
||||||
|
# we have no explicit effects but it's a forward declaration and so it's
|
||||||
|
# stated there are no additional effects, so simply propagate them:
|
||||||
propagateEffects(tracked, n, n.sym)
|
propagateEffects(tracked, n, n.sym)
|
||||||
else:
|
else:
|
||||||
|
# we have no explicit effects so assume the worst:
|
||||||
addEffect(tracked, createRaise(n))
|
addEffect(tracked, createRaise(n))
|
||||||
addTag(tracked, createTag(n))
|
addTag(tracked, createTag(n))
|
||||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
||||||
# assume GcUnsafe unless in its type:
|
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||||
if notGcSafe(op):
|
if notGcSafe(op):
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
else:
|
else:
|
||||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
||||||
if notGcSafe(op):
|
if notGcSafe(op):
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
notNilCheck(tracked, n, paramType)
|
notNilCheck(tracked, n, paramType)
|
||||||
|
|
||||||
|
|
@ -510,9 +508,6 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
|
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
|
||||||
if a.kind == nkSym and a.sym == tracked.owner:
|
if a.kind == nkSym and a.sym == tracked.owner:
|
||||||
tracked.isRecursive = true
|
tracked.isRecursive = true
|
||||||
elif notGcSafe(op) and not importedFromC(a):
|
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
|
||||||
tracked.gcUnsafe = true
|
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||||
propagateEffects(tracked, n, a.sym)
|
propagateEffects(tracked, n, a.sym)
|
||||||
|
|
@ -528,6 +523,11 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
||||||
|
if notGcSafe(op) and not importedFromC(a):
|
||||||
|
# and it's not a recursive call:
|
||||||
|
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||||
|
message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
|
tracked.gcUnsafe = true
|
||||||
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
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}:
|
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||||
# may not look like an assignment, but it is:
|
# may not look like an assignment, but it is:
|
||||||
|
|
@ -636,10 +636,6 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||||
if not isNil(tagsSpec):
|
if not isNil(tagsSpec):
|
||||||
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
||||||
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
||||||
let usesSpec = effectSpec(p, wUses)
|
|
||||||
if not isNil(usesSpec):
|
|
||||||
checkRaisesSpec(usesSpec, actual.sons[usesEffects],
|
|
||||||
"may use an unlisted global variable: ", hints=off, symbolPredicate)
|
|
||||||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||||
branch.name.s)
|
branch.name.s)
|
||||||
|
|
@ -651,16 +647,13 @@ proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||||
let
|
let
|
||||||
raisesSpec = effectSpec(n, wRaises)
|
raisesSpec = effectSpec(n, wRaises)
|
||||||
tagsSpec = effectSpec(n, wTags)
|
tagsSpec = effectSpec(n, wTags)
|
||||||
usesSpec = effectSpec(n, wUses)
|
if not isNil(raisesSpec) or not isNil(tagsSpec):
|
||||||
if not isNil(raisesSpec) or not isNil(tagsSpec) or not isNil(usesSpec):
|
|
||||||
internalAssert effects.len == 0
|
internalAssert effects.len == 0
|
||||||
newSeq(effects.sons, effectListLen)
|
newSeq(effects.sons, effectListLen)
|
||||||
if not isNil(raisesSpec):
|
if not isNil(raisesSpec):
|
||||||
effects.sons[exceptionEffects] = raisesSpec
|
effects.sons[exceptionEffects] = raisesSpec
|
||||||
if not isNil(tagsSpec):
|
if not isNil(tagsSpec):
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
if not isNil(usesSpec):
|
|
||||||
effects.sons[usesEffects] = usesSpec
|
|
||||||
|
|
||||||
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||||
newSeq(effects.sons, effectListLen)
|
newSeq(effects.sons, effectListLen)
|
||||||
|
|
@ -705,16 +698,10 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
# after the check, use the formal spec:
|
# after the check, use the formal spec:
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
|
|
||||||
when trackGlobals:
|
|
||||||
let usesSpec = effectSpec(p, wUses)
|
|
||||||
if not isNil(usesSpec):
|
|
||||||
checkRaisesSpec(usesSpec, t.uses,
|
|
||||||
"uses an unlisted global variable: ", hints=on, symbolPredicate)
|
|
||||||
effects.sons[usesEffects] = usesSpec
|
|
||||||
if optThreadAnalysis in gGlobalOptions:
|
if optThreadAnalysis in gGlobalOptions:
|
||||||
if sfThread in s.flags and t.gcUnsafe:
|
if sfThread in s.flags and t.gcUnsafe:
|
||||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||||
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
||||||
|
|
||||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
|
if n.kind != nkContinueStmt:
|
||||||
var s: PSym
|
var s: PSym
|
||||||
case n.sons[0].kind
|
case n.sons[0].kind
|
||||||
of nkIdent: s = lookUp(c, n.sons[0])
|
of nkIdent: s = lookUp(c, n.sons[0])
|
||||||
|
|
@ -36,6 +37,8 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
suggestSym(x.info, s)
|
suggestSym(x.info, s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||||
|
else:
|
||||||
|
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||||
localError(n.info, errInvalidControlFlowX,
|
localError(n.info, errInvalidControlFlowX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
@ -661,7 +664,8 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
||||||
var call = n.sons[length-2]
|
var call = n.sons[length-2]
|
||||||
let isCallExpr = call.kind in nkCallKinds
|
let isCallExpr = call.kind in nkCallKinds
|
||||||
if isCallExpr and call[0].kind == nkSym and call[0].sym.magic != mNone:
|
if isCallExpr and call[0].kind == nkSym and
|
||||||
|
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
|
||||||
if call.sons[0].sym.magic == mOmpParFor:
|
if call.sons[0].sym.magic == mOmpParFor:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n)
|
||||||
result.kind = nkParForStmt
|
result.kind = nkParForStmt
|
||||||
|
|
@ -1008,6 +1012,31 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||||
addResult(c, s.typ.sons[0], n.info, s.kind)
|
addResult(c, s.typ.sons[0], n.info, s.kind)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
|
|
||||||
|
proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
|
case s.name.s.normalize
|
||||||
|
of "destroy": doDestructorStuff(c, s, n)
|
||||||
|
of "deepcopy":
|
||||||
|
if s.typ.len == 2 and
|
||||||
|
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
|
||||||
|
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||||
|
# Note: we store the deepCopy in the base of the pointer to mitigate
|
||||||
|
# the problem that pointers are structural types:
|
||||||
|
let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||||
|
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
|
else:
|
||||||
|
localError(n.info, errGenerated,
|
||||||
|
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
||||||
|
else:
|
||||||
|
localError(n.info, errGenerated,
|
||||||
|
"cannot bind 'deepCopy' to: " & typeToString(t))
|
||||||
|
else:
|
||||||
|
localError(n.info, errGenerated,
|
||||||
|
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
||||||
|
of "=": discard
|
||||||
|
else: localError(n.info, errGenerated,
|
||||||
|
"'destroy' or 'deepCopy' expected for 'override'")
|
||||||
|
|
||||||
type
|
type
|
||||||
TProcCompilationSteps = enum
|
TProcCompilationSteps = enum
|
||||||
stepRegisterSymbol,
|
stepRegisterSymbol,
|
||||||
|
|
@ -1124,7 +1153,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
popOwner()
|
popOwner()
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
s.options = gOptions
|
s.options = gOptions
|
||||||
if sfDestructor in s.flags: doDestructorStuff(c, s, n)
|
if sfOverriden in s.flags: semOverride(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!
|
# for DLL generation it is annoying to check for sfImportc!
|
||||||
if sfBorrow in s.flags:
|
if sfBorrow in s.flags:
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ proc hasGenericArguments*(n: PNode): bool =
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
# This is needed fo tgenericshardcases
|
# This is needed for tgenericshardcases
|
||||||
# It's possible that a generic param will be used in a proc call to a
|
# 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
|
# typedesc accepting proc. After generic param substitution, such procs
|
||||||
# should be optionally instantiated with the correct type. In order to
|
# should be optionally instantiated with the correct type. In order to
|
||||||
|
|
@ -216,12 +216,16 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||||
result.typ = replaceTypeVarsT(cl, s.typ)
|
result.typ = replaceTypeVarsT(cl, s.typ)
|
||||||
result.ast = replaceTypeVarsN(cl, s.ast)
|
result.ast = replaceTypeVarsN(cl, s.ast)
|
||||||
|
|
||||||
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
result = PType(idTableGet(cl.typeMap, t))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||||
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
||||||
result = errorType(cl.c)
|
result = errorType(cl.c)
|
||||||
|
# In order to prevent endless recursions, we must remember
|
||||||
|
# this bad lookup and replace it with errorType everywhere.
|
||||||
|
# These code paths are only active in nimrod check
|
||||||
|
idTablePut(cl.typeMap, t, result)
|
||||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||||
internalError(cl.info, "substitution with generic parameter")
|
internalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
||||||
|
|
@ -353,7 +357,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
||||||
result = t
|
result = errorType(cl.c)
|
||||||
#result = replaceTypeVarsT(cl, lastSon(t))
|
#result = replaceTypeVarsT(cl, lastSon(t))
|
||||||
|
|
||||||
of tyFromExpr:
|
of tyFromExpr:
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
inc argsCount
|
inc argsCount
|
||||||
|
|
||||||
if pass == passCmd2:
|
if pass == passCmd2:
|
||||||
if optRun notin gGlobalOptions and arguments != "":
|
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
|
||||||
rawMessage(errArgsNeedRunOption, [])
|
rawMessage(errArgsNeedRunOption, [])
|
||||||
|
|
||||||
proc serve*(action: proc (){.nimcall.}) =
|
proc serve*(action: proc (){.nimcall.}) =
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,9 @@ proc compileCCode*(ccode: string) =
|
||||||
setupEnvironment()
|
setupEnvironment()
|
||||||
discard compileString(gTinyC, ccode)
|
discard compileString(gTinyC, ccode)
|
||||||
|
|
||||||
proc run*() =
|
proc run*(args: string) =
|
||||||
var a: array[0..1, cstring]
|
var s = @[cstring(gProjectName)] & map(split(args), proc(x: string): cstring = cstring(x))
|
||||||
a[0] = ""
|
var err = tinyc.run(gTinyC, cint(len(s)), cast[cstringArray](addr(s[0]))) != 0'i32
|
||||||
a[1] = ""
|
|
||||||
var err = tinyc.run(gTinyC, 0'i32, cast[cstringArray](addr(a))) != 0'i32
|
|
||||||
closeCCState(gTinyC)
|
closeCCState(gTinyC)
|
||||||
if err: rawMessage(errExecutionOfProgramFailed, "")
|
if err: rawMessage(errExecutionOfProgramFailed, "")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
template tests*(body: stmt) {.immediate.} =
|
template tests*(body: stmt) {.immediate.} =
|
||||||
when defined(selftest):
|
when defined(selftest):
|
||||||
when not defined(unittest): import unittest
|
when not declared(unittest): import unittest
|
||||||
body
|
body
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
# * inlines iterators
|
# * inlines iterators
|
||||||
# * inlines constants
|
# * inlines constants
|
||||||
# * performes constant folding
|
# * performes constant folding
|
||||||
# * converts "continue" to "break"
|
# * converts "continue" to "break"; disambiguates "break"
|
||||||
# * introduces method dispatchers
|
# * introduces method dispatchers
|
||||||
# * performs lambda lifting for closure support
|
# * performs lambda lifting for closure support
|
||||||
|
|
||||||
|
|
@ -44,7 +44,6 @@ type
|
||||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||||
nestedProcs: int # > 0 if we are in a nested proc
|
nestedProcs: int # > 0 if we are in a nested proc
|
||||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
inLoop: int # > 0 if we are in a loop
|
|
||||||
PTransf = ref TTransfContext
|
PTransf = ref TTransfContext
|
||||||
|
|
||||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||||
|
|
@ -201,6 +200,18 @@ proc newLabel(c: PTransf, n: PNode): PSym =
|
||||||
result = newSym(skLabel, nil, getCurrOwner(c), n.info)
|
result = newSym(skLabel, nil, getCurrOwner(c), n.info)
|
||||||
result.name = getIdent(genPrefix & $result.id)
|
result.name = getIdent(genPrefix & $result.id)
|
||||||
|
|
||||||
|
proc freshLabels(c: PTransf, n: PNode; symMap: var TIdTable) =
|
||||||
|
if n.kind in {nkBlockStmt, nkBlockExpr}:
|
||||||
|
if n.sons[0].kind == nkSym:
|
||||||
|
let x = newLabel(c, n[0])
|
||||||
|
idTablePut(symMap, n[0].sym, x)
|
||||||
|
n.sons[0].sym = x
|
||||||
|
if n.kind == nkSym and n.sym.kind == skLabel:
|
||||||
|
let x = PSym(idTableGet(symMap, n.sym))
|
||||||
|
if x != nil: n.sym = x
|
||||||
|
else:
|
||||||
|
for i in 0 .. <safeLen(n): freshLabels(c, n.sons[i], symMap)
|
||||||
|
|
||||||
proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
||||||
var labl: PSym
|
var labl: PSym
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
|
|
@ -213,14 +224,6 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
|
||||||
if c.inLoop > 0 or n.sons[0].kind != nkEmpty:
|
|
||||||
result = n.PTransNode
|
|
||||||
else:
|
|
||||||
let labl = c.breakSyms[c.breakSyms.high]
|
|
||||||
result = transformSons(c, n)
|
|
||||||
result[0] = newSymNode(labl).PTransNode
|
|
||||||
|
|
||||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
# What if it contains "continue" and "break"? "break" needs
|
# What if it contains "continue" and "break"? "break" needs
|
||||||
# an explicit label too, but not the same!
|
# an explicit label too, but not the same!
|
||||||
|
|
@ -239,6 +242,37 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result = transform(c, n)
|
result = transform(c, n)
|
||||||
|
|
||||||
|
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
||||||
|
if c.inlining > 0:
|
||||||
|
result = transformSons(c, n)
|
||||||
|
else:
|
||||||
|
let labl = newLabel(c, n)
|
||||||
|
c.breakSyms.add(labl)
|
||||||
|
result = newTransNode(nkBlockStmt, n.info, 2)
|
||||||
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
|
var body = newTransNode(n)
|
||||||
|
for i in 0..n.len-2:
|
||||||
|
body[i] = transform(c, n.sons[i])
|
||||||
|
body[<n.len] = transformLoopBody(c, n.sons[<n.len])
|
||||||
|
result[1] = body
|
||||||
|
discard c.breakSyms.pop
|
||||||
|
|
||||||
|
proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
||||||
|
if n.sons[0].kind != nkEmpty or c.inlining > 0:
|
||||||
|
result = n.PTransNode
|
||||||
|
when false:
|
||||||
|
let lablCopy = idNodeTableGet(c.transCon.mapping, n.sons[0].sym)
|
||||||
|
if lablCopy.isNil:
|
||||||
|
result = n.PTransNode
|
||||||
|
else:
|
||||||
|
result = newTransNode(n.kind, n.info, 1)
|
||||||
|
result[0] = lablCopy.PTransNode
|
||||||
|
else:
|
||||||
|
let labl = c.breakSyms[c.breakSyms.high]
|
||||||
|
result = transformSons(c, n)
|
||||||
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||||
|
|
@ -424,20 +458,32 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
|
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
var call = n.sons[length - 2]
|
var call = n.sons[length - 2]
|
||||||
|
|
||||||
|
let labl = newLabel(c, n)
|
||||||
|
c.breakSyms.add(labl)
|
||||||
|
result = newTransNode(nkBlockStmt, n.info, 2)
|
||||||
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
if call.typ.kind != tyIter and
|
if call.typ.kind != tyIter and
|
||||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].sym.kind != skIterator):
|
call.sons[0].sym.kind != skIterator):
|
||||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||||
return lambdalifting.liftForLoop(n).PTransNode
|
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||||
#InternalError(call.info, "transformFor")
|
discard c.breakSyms.pop
|
||||||
|
return result
|
||||||
|
|
||||||
#echo "transforming: ", renderTree(n)
|
#echo "transforming: ", renderTree(n)
|
||||||
result = newTransNode(nkStmtList, n.info, 0)
|
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
||||||
|
|
||||||
var loopBody = transformLoopBody(c, n.sons[length-1])
|
var loopBody = transformLoopBody(c, n.sons[length-1])
|
||||||
|
|
||||||
|
result[1] = stmtList
|
||||||
|
discard c.breakSyms.pop
|
||||||
|
|
||||||
var v = newNodeI(nkVarSection, n.info)
|
var v = newNodeI(nkVarSection, n.info)
|
||||||
for i in countup(0, length - 3):
|
for i in countup(0, length - 3):
|
||||||
addVar(v, copyTree(n.sons[i])) # declare new vars
|
addVar(v, copyTree(n.sons[i])) # declare new vars
|
||||||
add(result, v.PTransNode)
|
add(stmtList, v.PTransNode)
|
||||||
|
|
||||||
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
||||||
# iterator!
|
# iterator!
|
||||||
|
|
@ -459,21 +505,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate a temporary and produce an assignment statement:
|
# generate a temporary and produce an assignment statement:
|
||||||
var temp = newTemp(c, formal.typ, formal.info)
|
var temp = newTemp(c, formal.typ, formal.info)
|
||||||
addVar(v, newSymNode(temp))
|
addVar(v, newSymNode(temp))
|
||||||
add(result, newAsgnStmt(c, newSymNode(temp), arg.PTransNode))
|
add(stmtList, newAsgnStmt(c, newSymNode(temp), arg.PTransNode))
|
||||||
idNodeTablePut(newC.mapping, formal, newSymNode(temp))
|
idNodeTablePut(newC.mapping, formal, newSymNode(temp))
|
||||||
of paVarAsgn:
|
of paVarAsgn:
|
||||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||||
idNodeTablePut(newC.mapping, formal, arg)
|
idNodeTablePut(newC.mapping, formal, arg)
|
||||||
# XXX BUG still not correct if the arg has a side effect!
|
# XXX BUG still not correct if the arg has a side effect!
|
||||||
var body = iter.getBody
|
var body = iter.getBody.copyTree
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
|
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
||||||
|
var symMap: TIdTable
|
||||||
|
initIdTable symMap
|
||||||
|
freshLabels(c, body, symMap)
|
||||||
|
|
||||||
inc(c.inlining)
|
inc(c.inlining)
|
||||||
add(result, transform(c, body))
|
add(stmtList, transform(c, body))
|
||||||
#findWrongOwners(c, result.pnode)
|
#findWrongOwners(c, stmtList.pnode)
|
||||||
dec(c.inlining)
|
dec(c.inlining)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
# echo "transformed: ", result.PNode.renderTree
|
# echo "transformed: ", stmtList.PNode.renderTree
|
||||||
|
|
||||||
proc getMagicOp(call: PNode): TMagic =
|
proc getMagicOp(call: PNode): TMagic =
|
||||||
if call.sons[0].kind == nkSym and
|
if call.sons[0].kind == nkSym and
|
||||||
|
|
@ -643,25 +694,16 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
if n.kind == nkMethodDef: methodDef(s, false)
|
if n.kind == nkMethodDef: methodDef(s, false)
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkForStmt:
|
of nkForStmt:
|
||||||
inc c.inLoop
|
|
||||||
result = transformFor(c, n)
|
result = transformFor(c, n)
|
||||||
dec c.inLoop
|
|
||||||
of nkParForStmt:
|
of nkParForStmt:
|
||||||
inc c.inLoop
|
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
dec c.inLoop
|
|
||||||
of nkCaseStmt: result = transformCase(c, n)
|
of nkCaseStmt: result = transformCase(c, n)
|
||||||
of nkContinueStmt:
|
of nkContinueStmt:
|
||||||
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
||||||
var labl = c.contSyms[c.contSyms.high]
|
var labl = c.contSyms[c.contSyms.high]
|
||||||
add(result, PTransNode(newSymNode(labl)))
|
add(result, PTransNode(newSymNode(labl)))
|
||||||
of nkBreakStmt: result = transformBreak(c, n)
|
of nkBreakStmt: result = transformBreak(c, n)
|
||||||
of nkWhileStmt:
|
of nkWhileStmt: result = transformWhile(c, n)
|
||||||
inc c.inLoop
|
|
||||||
result = newTransNode(n)
|
|
||||||
result[0] = transform(c, n.sons[0])
|
|
||||||
result[1] = transformLoopBody(c, n.sons[1])
|
|
||||||
dec c.inLoop
|
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
result = transformCall(c, n)
|
result = transformCall(c, n)
|
||||||
|
|
@ -740,6 +782,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
# result = lambdalifting.liftIterator(prc, result)
|
# result = lambdalifting.liftIterator(prc, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
when useEffectSystem: trackProc(prc, result)
|
when useEffectSystem: trackProc(prc, result)
|
||||||
|
if prc.name.s == "testbody":
|
||||||
|
echo renderTree(result)
|
||||||
|
|
||||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||||
if nfTransf in n.flags:
|
if nfTransf in n.flags:
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ proc isPureObject(typ: PType): bool =
|
||||||
|
|
||||||
proc getOrdValue(n: PNode): BiggestInt =
|
proc getOrdValue(n: PNode): BiggestInt =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCharLit..nkInt64Lit: result = n.intVal
|
of nkCharLit..nkUInt64Lit: result = n.intVal
|
||||||
of nkNilLit: result = 0
|
of nkNilLit: result = 0
|
||||||
of nkHiddenStdConv: result = getOrdValue(n.sons[1])
|
of nkHiddenStdConv: result = getOrdValue(n.sons[1])
|
||||||
else:
|
else:
|
||||||
|
|
@ -582,6 +582,9 @@ proc firstOrd(t: PType): BiggestInt =
|
||||||
of tyGenericInst, tyDistinct, tyConst, tyMutable,
|
of tyGenericInst, tyDistinct, tyConst, tyMutable,
|
||||||
tyTypeDesc, tyFieldAccessor:
|
tyTypeDesc, tyFieldAccessor:
|
||||||
result = firstOrd(lastSon(t))
|
result = firstOrd(lastSon(t))
|
||||||
|
of tyOrdinal:
|
||||||
|
if t.len > 0: result = firstOrd(lastSon(t))
|
||||||
|
else: internalError("invalid kind for first(" & $t.kind & ')')
|
||||||
else:
|
else:
|
||||||
internalError("invalid kind for first(" & $t.kind & ')')
|
internalError("invalid kind for first(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
@ -617,6 +620,9 @@ proc lastOrd(t: PType): BiggestInt =
|
||||||
tyTypeDesc, tyFieldAccessor:
|
tyTypeDesc, tyFieldAccessor:
|
||||||
result = lastOrd(lastSon(t))
|
result = lastOrd(lastSon(t))
|
||||||
of tyProxy: result = 0
|
of tyProxy: result = 0
|
||||||
|
of tyOrdinal:
|
||||||
|
if t.len > 0: result = lastOrd(lastSon(t))
|
||||||
|
else: internalError("invalid kind for last(" & $t.kind & ')')
|
||||||
else:
|
else:
|
||||||
internalError("invalid kind for last(" & $t.kind & ')')
|
internalError("invalid kind for last(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
@ -907,9 +913,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameTypeAux(a.sons[0], b.sons[0], c)
|
result = sameTypeAux(a.sons[0], b.sons[0], c)
|
||||||
else:
|
else:
|
||||||
result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
|
result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
|
||||||
of tyEnum, tyForward, tyProxy:
|
of tyEnum, tyForward:
|
||||||
# XXX generic enums do not make much sense, but require structural checking
|
# XXX generic enums do not make much sense, but require structural checking
|
||||||
result = a.id == b.id and sameFlags(a, b)
|
result = a.id == b.id and sameFlags(a, b)
|
||||||
|
of tyError:
|
||||||
|
result = b.kind == tyError
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
cycleCheck()
|
cycleCheck()
|
||||||
result = sameTuple(a, b, c) and sameFlags(a, b)
|
result = sameTuple(a, b, c) and sameFlags(a, b)
|
||||||
|
|
@ -1363,3 +1371,35 @@ proc containsCompileTimeOnly*(t: PType): bool =
|
||||||
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
type
|
||||||
|
OrdinalType* = enum
|
||||||
|
NoneLike, IntLike, FloatLike
|
||||||
|
|
||||||
|
proc classify*(t: PType): OrdinalType =
|
||||||
|
## for convenient type checking:
|
||||||
|
if t == nil:
|
||||||
|
result = NoneLike
|
||||||
|
else:
|
||||||
|
case skipTypes(t, abstractVarRange).kind
|
||||||
|
of tyFloat..tyFloat128: result = FloatLike
|
||||||
|
of tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyChar, tyEnum:
|
||||||
|
result = IntLike
|
||||||
|
else: result = NoneLike
|
||||||
|
|
||||||
|
proc skipConv*(n: PNode): PNode =
|
||||||
|
result = n
|
||||||
|
case n.kind
|
||||||
|
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||||
|
# only skip the conversion if it doesn't lose too important information
|
||||||
|
# (see bug #1334)
|
||||||
|
if n.sons[0].typ.classify == n.typ.classify:
|
||||||
|
result = n.sons[0]
|
||||||
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
|
if n.sons[1].typ.classify == n.typ.classify:
|
||||||
|
result = n.sons[1]
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
proc skipConvTakeType*(n: PNode): PNode =
|
||||||
|
result = n.skipConv
|
||||||
|
result.typ = n.typ
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import ast except getstr
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
||||||
parser, vmdeps, idents, trees, renderer, options, transf
|
parser, vmdeps, idents, trees, renderer, options, transf, parseutils
|
||||||
|
|
||||||
from semfold import leValueConv, ordinalValToString
|
from semfold import leValueConv, ordinalValToString
|
||||||
from evaltempl import evalTemplate
|
from evaltempl import evalTemplate
|
||||||
|
|
@ -87,9 +87,7 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
|
||||||
when not defined(nimComputedGoto):
|
when not defined(nimComputedGoto):
|
||||||
{.pragma: computedGoto.}
|
{.pragma: computedGoto.}
|
||||||
|
|
||||||
proc myreset(n: var TFullReg) =
|
proc myreset(n: var TFullReg) = reset(n)
|
||||||
when defined(system.reset):
|
|
||||||
reset(n)
|
|
||||||
|
|
||||||
template ensureKind(k: expr) {.immediate, dirty.} =
|
template ensureKind(k: expr) {.immediate, dirty.} =
|
||||||
if regs[ra].kind != k:
|
if regs[ra].kind != k:
|
||||||
|
|
@ -776,6 +774,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
createStr regs[ra]
|
createStr regs[ra]
|
||||||
regs[ra].node.strVal = substr(regs[rb].node.strVal,
|
regs[ra].node.strVal = substr(regs[rb].node.strVal,
|
||||||
regs[rc].intVal.int, regs[rd].intVal.int)
|
regs[rc].intVal.int, regs[rd].intVal.int)
|
||||||
|
of opcParseFloat:
|
||||||
|
decodeBC(rkInt)
|
||||||
|
inc pc
|
||||||
|
assert c.code[pc].opcode == opcParseFloat
|
||||||
|
let rd = c.code[pc].regA
|
||||||
|
var rcAddr = addr(regs[rc])
|
||||||
|
if rcAddr.kind == rkRegisterAddr: rcAddr = rcAddr.regAddr
|
||||||
|
elif regs[rc].kind != rkFloat:
|
||||||
|
myreset(regs[rc])
|
||||||
|
regs[rc].kind = rkFloat
|
||||||
|
regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal,
|
||||||
|
rcAddr.floatVal, regs[rd].intVal.int)
|
||||||
of opcRangeChck:
|
of opcRangeChck:
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
let rc = instr.regC
|
let rc = instr.regC
|
||||||
|
|
@ -1068,6 +1078,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNKind:
|
of opcNKind:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
regs[ra].intVal = ord(regs[rb].node.kind)
|
regs[ra].intVal = ord(regs[rb].node.kind)
|
||||||
|
c.comesFromHeuristic = regs[rb].node.info
|
||||||
of opcNIntVal:
|
of opcNIntVal:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
let a = regs[rb].node
|
let a = regs[rb].node
|
||||||
|
|
@ -1243,8 +1254,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
internalError(c.debug[pc],
|
internalError(c.debug[pc],
|
||||||
"request to create a NimNode of invalid kind")
|
"request to create a NimNode of invalid kind")
|
||||||
let cc = regs[rc].node
|
let cc = regs[rc].node
|
||||||
|
|
||||||
regs[ra].node = newNodeI(TNodeKind(int(k)),
|
regs[ra].node = newNodeI(TNodeKind(int(k)),
|
||||||
if cc.kind == nkNilLit: c.debug[pc] else: cc.info)
|
if cc.kind != nkNilLit:
|
||||||
|
cc.info
|
||||||
|
elif c.comesFromHeuristic.line > -1:
|
||||||
|
c.comesFromHeuristic
|
||||||
|
elif c.callsite != nil and c.callsite.safeLen > 1:
|
||||||
|
c.callsite[1].info
|
||||||
|
else:
|
||||||
|
c.debug[pc])
|
||||||
regs[ra].node.flags.incl nfIsRef
|
regs[ra].node.flags.incl nfIsRef
|
||||||
of opcNCopyNimNode:
|
of opcNCopyNimNode:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ type
|
||||||
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
|
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
|
||||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||||
opcSwap, opcIsNil, opcOf, opcIs,
|
opcSwap, opcIsNil, opcOf, opcIs,
|
||||||
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
|
||||||
opcNarrowS, opcNarrowU,
|
opcNarrowS, opcNarrowU,
|
||||||
|
|
||||||
opcAddStrCh,
|
opcAddStrCh,
|
||||||
|
|
@ -188,6 +188,7 @@ type
|
||||||
features*: TSandboxFlags
|
features*: TSandboxFlags
|
||||||
traceActive*: bool
|
traceActive*: bool
|
||||||
loopIterations*: int
|
loopIterations*: int
|
||||||
|
comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
|
||||||
|
|
||||||
TPosition* = distinct int
|
TPosition* = distinct int
|
||||||
|
|
||||||
|
|
@ -196,7 +197,8 @@ type
|
||||||
proc newCtx*(module: PSym): PCtx =
|
proc newCtx*(module: PSym): PCtx =
|
||||||
PCtx(code: @[], debug: @[],
|
PCtx(code: @[], debug: @[],
|
||||||
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
|
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
|
||||||
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations)
|
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
|
||||||
|
comesFromHeuristic: unknownLineInfo())
|
||||||
|
|
||||||
proc refresh*(c: PCtx, module: PSym) =
|
proc refresh*(c: PCtx, module: PSym) =
|
||||||
c.module = module
|
c.module = module
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ import ast, types, msgs, osproc, streams, options
|
||||||
proc readOutput(p: PProcess): string =
|
proc readOutput(p: PProcess): string =
|
||||||
result = ""
|
result = ""
|
||||||
var output = p.outputStream
|
var output = p.outputStream
|
||||||
discard p.waitForExit
|
|
||||||
while not output.atEnd:
|
while not output.atEnd:
|
||||||
result.add(output.readLine)
|
result.add(output.readLine)
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.setLen(result.len - "\n".len)
|
result.setLen(result.len - "\n".len)
|
||||||
|
discard p.waitForExit
|
||||||
|
|
||||||
proc opGorge*(cmd, input: string): string =
|
proc opGorge*(cmd, input: string): string =
|
||||||
var p = startCmd(cmd)
|
var p = startCmd(cmd)
|
||||||
|
|
|
||||||
|
|
@ -43,18 +43,19 @@ type
|
||||||
proc debugInfo(info: TLineInfo): string =
|
proc debugInfo(info: TLineInfo): string =
|
||||||
result = info.toFilename.splitFile.name & ":" & $info.line
|
result = info.toFilename.splitFile.name & ":" & $info.line
|
||||||
|
|
||||||
proc codeListing(c: PCtx, result: var string, start=0) =
|
proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
|
||||||
# first iteration: compute all necessary labels:
|
# first iteration: compute all necessary labels:
|
||||||
var jumpTargets = initIntSet()
|
var jumpTargets = initIntSet()
|
||||||
|
|
||||||
for i in start.. < c.code.len:
|
let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1)
|
||||||
|
for i in start..last:
|
||||||
let x = c.code[i]
|
let x = c.code[i]
|
||||||
if x.opcode in relativeJumps:
|
if x.opcode in relativeJumps:
|
||||||
jumpTargets.incl(i+x.regBx-wordExcess)
|
jumpTargets.incl(i+x.regBx-wordExcess)
|
||||||
|
|
||||||
# for debugging purposes
|
# for debugging purposes
|
||||||
var i = start
|
var i = start
|
||||||
while i < c.code.len:
|
while i <= last:
|
||||||
if i in jumpTargets: result.addf("L$1:\n", i)
|
if i in jumpTargets: result.addf("L$1:\n", i)
|
||||||
let x = c.code[i]
|
let x = c.code[i]
|
||||||
|
|
||||||
|
|
@ -82,9 +83,9 @@ proc codeListing(c: PCtx, result: var string, start=0) =
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
proc echoCode*(c: PCtx, start=0) {.deprecated.} =
|
proc echoCode*(c: PCtx, start=0; last = -1) {.deprecated.} =
|
||||||
var buf = ""
|
var buf = ""
|
||||||
codeListing(c, buf, start)
|
codeListing(c, buf, start, last)
|
||||||
echo buf
|
echo buf
|
||||||
|
|
||||||
proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||||
|
|
@ -495,6 +496,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.freeTempRange(x, n.len)
|
c.freeTempRange(x, n.len)
|
||||||
|
|
||||||
template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
|
template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
|
||||||
|
proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
|
||||||
|
|
||||||
proc needsAsgnPatch(n: PNode): bool =
|
proc needsAsgnPatch(n: PNode): bool =
|
||||||
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
|
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
|
||||||
|
|
@ -637,8 +639,10 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
|
var x = n.sons[1]
|
||||||
|
if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0]
|
||||||
let
|
let
|
||||||
dest = c.genx(n.sons[1], {gfAddrOf})
|
dest = c.genx(x)
|
||||||
tmp = c.genx(n.sons[2])
|
tmp = c.genx(n.sons[2])
|
||||||
c.gABC(n, opc, dest, tmp, 0)
|
c.gABC(n, opc, dest, tmp, 0)
|
||||||
#c.genAsgnPatch(n.sons[1], dest)
|
#c.genAsgnPatch(n.sons[1], dest)
|
||||||
|
|
@ -852,6 +856,24 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.freeTemp(tmp1)
|
c.freeTemp(tmp1)
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
c.freeTemp(tmp3)
|
c.freeTemp(tmp3)
|
||||||
|
of mParseBiggestFloat:
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
var d2: TRegister
|
||||||
|
# skip 'nkHiddenAddr':
|
||||||
|
let d2AsNode = n.sons[2].sons[0]
|
||||||
|
if needsAsgnPatch(d2AsNode):
|
||||||
|
d2 = c.getTemp(getSysType(tyFloat))
|
||||||
|
else:
|
||||||
|
d2 = c.genx(d2AsNode)
|
||||||
|
var
|
||||||
|
tmp1 = c.genx(n.sons[1])
|
||||||
|
tmp3 = c.genx(n.sons[3])
|
||||||
|
c.gABC(n, opcParseFloat, dest, tmp1, d2)
|
||||||
|
c.gABC(n, opcParseFloat, tmp3)
|
||||||
|
c.freeTemp(tmp1)
|
||||||
|
c.freeTemp(tmp3)
|
||||||
|
c.genAsgnPatch(d2AsNode, d2)
|
||||||
|
c.freeTemp(d2)
|
||||||
of mReset:
|
of mReset:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
var d = c.genx(n.sons[1])
|
var d = c.genx(n.sons[1])
|
||||||
|
|
@ -1035,6 +1057,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||||
# nkAddr we must not use 'unneededIndirection', but for deref we use it.
|
# nkAddr we must not use 'unneededIndirection', but for deref we use it.
|
||||||
if not isAddr and unneededIndirection(n.sons[0]):
|
if not isAddr and unneededIndirection(n.sons[0]):
|
||||||
gen(c, n.sons[0], dest, newflags)
|
gen(c, n.sons[0], dest, newflags)
|
||||||
|
elif isAddr and isGlobal(n.sons[0]):
|
||||||
|
gen(c, n.sons[0], dest, flags+{gfAddrOf})
|
||||||
else:
|
else:
|
||||||
let tmp = c.genx(n.sons[0], newflags)
|
let tmp = c.genx(n.sons[0], newflags)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
|
@ -1075,6 +1099,8 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||||
# XXX generate type initialization here?
|
# XXX generate type initialization here?
|
||||||
if v.position == 0:
|
if v.position == 0:
|
||||||
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
|
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
|
||||||
|
if c.prc.maxSlots >= high(TRegister):
|
||||||
|
internalError(v.info, "cannot generate code; too many registers required")
|
||||||
v.position = c.prc.maxSlots
|
v.position = c.prc.maxSlots
|
||||||
c.prc.slots[v.position] = (inUse: true,
|
c.prc.slots[v.position] = (inUse: true,
|
||||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||||
|
|
@ -1098,7 +1124,6 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||||
# we need to ensure that we don't evaluate 'x' here:
|
# we need to ensure that we don't evaluate 'x' here:
|
||||||
# proc foo() = var x ...
|
# proc foo() = var x ...
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if s.position == 0:
|
|
||||||
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
||||||
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
|
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
|
||||||
cannotEval(n)
|
cannotEval(n)
|
||||||
|
|
@ -1228,6 +1253,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
c.gABx(n, opcLdGlobal, cc, s.position)
|
c.gABx(n, opcLdGlobal, cc, s.position)
|
||||||
c.gABC(n, opcNodeToReg, dest, cc)
|
c.gABC(n, opcNodeToReg, dest, cc)
|
||||||
c.freeTemp(cc)
|
c.freeTemp(cc)
|
||||||
|
elif gfAddrOf in flags:
|
||||||
|
c.gABx(n, opcLdGlobalAddr, dest, s.position)
|
||||||
else:
|
else:
|
||||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ type
|
||||||
wContinue, wConverter, wDiscard, wDistinct, wDiv, wDo,
|
wContinue, wConverter, wDiscard, wDistinct, wDiv, wDo,
|
||||||
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
||||||
wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn,
|
wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn,
|
||||||
wInclude, wInterface, wIs, wIsnot, wIterator, wLambda, wLet,
|
wInclude, wInterface, wIs, wIsnot, wIterator, wLet,
|
||||||
wMacro, wMethod, wMixin, wMod, wNil,
|
wMacro, wMethod, wMixin, wMod, wNil,
|
||||||
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
|
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
|
||||||
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
|
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
|
||||||
|
|
@ -39,7 +39,7 @@ type
|
||||||
|
|
||||||
wDestroy,
|
wDestroy,
|
||||||
|
|
||||||
wImmediate, wDestructor, wDelegator,
|
wImmediate, wDestructor, wDelegator, wOverride,
|
||||||
wImportCpp, wImportObjC,
|
wImportCpp, wImportObjC,
|
||||||
wImportCompilerProc,
|
wImportCompilerProc,
|
||||||
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
||||||
|
|
@ -64,7 +64,7 @@ type
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||||
wAsmNoStackFrame,
|
wAsmNoStackFrame,
|
||||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wUses,
|
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
|
||||||
|
|
||||||
wAuto, wBool, wCatch, wChar, wClass,
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||||
|
|
@ -107,7 +107,7 @@ const
|
||||||
"elif", "else", "end", "enum", "except", "export",
|
"elif", "else", "end", "enum", "except", "export",
|
||||||
"finally", "for", "from", "generic", "if",
|
"finally", "for", "from", "generic", "if",
|
||||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||||
"lambda", "let",
|
"let",
|
||||||
"macro", "method", "mixin", "mod", "nil", "not", "notin",
|
"macro", "method", "mixin", "mod", "nil", "not", "notin",
|
||||||
"object", "of", "or",
|
"object", "of", "or",
|
||||||
"out", "proc", "ptr", "raise", "ref", "return",
|
"out", "proc", "ptr", "raise", "ref", "return",
|
||||||
|
|
@ -122,7 +122,7 @@ const
|
||||||
|
|
||||||
"destroy",
|
"destroy",
|
||||||
|
|
||||||
"immediate", "destructor", "delegator",
|
"immediate", "destructor", "delegator", "override",
|
||||||
"importcpp", "importobjc",
|
"importcpp", "importobjc",
|
||||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||||
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
||||||
|
|
@ -147,7 +147,7 @@ const
|
||||||
"computedgoto", "injectstmt",
|
"computedgoto", "injectstmt",
|
||||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||||
"guard", "uses",
|
"guard", "locks",
|
||||||
|
|
||||||
"auto", "bool", "catch", "char", "class",
|
"auto", "bool", "catch", "char", "class",
|
||||||
"const_cast", "default", "delete", "double",
|
"const_cast", "default", "delete", "double",
|
||||||
|
|
|
||||||
139
config/nim.cfg
Normal file
139
config/nim.cfg
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
# Configuration file for the Nimrod Compiler.
|
||||||
|
# (c) 2013 Andreas Rumpf
|
||||||
|
|
||||||
|
# Feel free to edit the default values as you need.
|
||||||
|
|
||||||
|
# You may set environment variables with
|
||||||
|
# @putenv "key" "val"
|
||||||
|
# Environment variables cannot be used in the options, however!
|
||||||
|
|
||||||
|
cc = gcc
|
||||||
|
|
||||||
|
# example of how to setup a cross-compiler:
|
||||||
|
arm.linux.gcc.exe = "arm-linux-gcc"
|
||||||
|
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
||||||
|
|
||||||
|
path="$lib/core"
|
||||||
|
path="$lib/pure"
|
||||||
|
path="$lib/pure/collections"
|
||||||
|
path="$lib/pure/concurrency"
|
||||||
|
path="$lib/impure"
|
||||||
|
path="$lib/wrappers"
|
||||||
|
# path="$lib/wrappers/cairo"
|
||||||
|
# path="$lib/wrappers/gtk"
|
||||||
|
# path="$lib/wrappers/lua"
|
||||||
|
# path="$lib/wrappers/opengl"
|
||||||
|
path="$lib/wrappers/pcre"
|
||||||
|
path="$lib/wrappers/readline"
|
||||||
|
path="$lib/wrappers/sdl"
|
||||||
|
# path="$lib/wrappers/x11"
|
||||||
|
path="$lib/wrappers/zip"
|
||||||
|
path="$lib/wrappers/libffi"
|
||||||
|
path="$lib/windows"
|
||||||
|
path="$lib/posix"
|
||||||
|
path="$lib/js"
|
||||||
|
path="$lib/pure/unidecode"
|
||||||
|
|
||||||
|
@if nimbabel:
|
||||||
|
babelpath="$home/.babel/pkgs/"
|
||||||
|
@end
|
||||||
|
|
||||||
|
@if release or quick:
|
||||||
|
obj_checks:off
|
||||||
|
field_checks:off
|
||||||
|
range_checks:off
|
||||||
|
bound_checks:off
|
||||||
|
overflow_checks:off
|
||||||
|
assertions:off
|
||||||
|
stacktrace:off
|
||||||
|
linetrace:off
|
||||||
|
debugger:off
|
||||||
|
line_dir:off
|
||||||
|
dead_code_elim:on
|
||||||
|
@end
|
||||||
|
|
||||||
|
@if release:
|
||||||
|
opt:speed
|
||||||
|
@end
|
||||||
|
|
||||||
|
# additional options always passed to the compiler:
|
||||||
|
--parallel_build: "0" # 0 to auto-detect number of processors
|
||||||
|
|
||||||
|
hint[LineTooLong]=off
|
||||||
|
#hint[XDeclaredButNotUsed]=off
|
||||||
|
|
||||||
|
@if unix:
|
||||||
|
@if not bsd:
|
||||||
|
# -fopenmp
|
||||||
|
gcc.options.linker = "-ldl"
|
||||||
|
gpp.options.linker = "-ldl"
|
||||||
|
clang.options.linker = "-ldl"
|
||||||
|
tcc.options.linker = "-ldl"
|
||||||
|
@end
|
||||||
|
@if bsd or haiku:
|
||||||
|
# BSD got posix_spawn only recently, so we deactivate it for osproc:
|
||||||
|
define:useFork
|
||||||
|
# at least NetBSD has problems with thread local storage:
|
||||||
|
tlsEmulation:on
|
||||||
|
@end
|
||||||
|
@end
|
||||||
|
|
||||||
|
# Configuration for the Intel C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
icl.options.speed = "/Ox /arch:SSE2"
|
||||||
|
icl.options.always = "/nologo"
|
||||||
|
@end
|
||||||
|
|
||||||
|
# Configuration for the GNU C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
#gcc.path = r"$nimrod\dist\mingw\bin"
|
||||||
|
@if gcc:
|
||||||
|
tlsEmulation:on
|
||||||
|
@end
|
||||||
|
@end
|
||||||
|
|
||||||
|
@if macosx:
|
||||||
|
cc = clang
|
||||||
|
tlsEmulation:on
|
||||||
|
gcc.options.always = "-w -fasm-blocks"
|
||||||
|
gpp.options.always = "-w -fasm-blocks -fpermissive"
|
||||||
|
@else:
|
||||||
|
gcc.options.always = "-w"
|
||||||
|
gpp.options.always = "-w -fpermissive"
|
||||||
|
@end
|
||||||
|
|
||||||
|
gcc.options.speed = "-O3 -fno-strict-aliasing"
|
||||||
|
gcc.options.size = "-Os"
|
||||||
|
gcc.options.debug = "-g3 -O0"
|
||||||
|
|
||||||
|
gpp.options.speed = "-O3 -fno-strict-aliasing"
|
||||||
|
gpp.options.size = "-Os"
|
||||||
|
gpp.options.debug = "-g3 -O0"
|
||||||
|
#passl = "-pg"
|
||||||
|
|
||||||
|
# Configuration for the LLVM GCC compiler:
|
||||||
|
llvm_gcc.options.debug = "-g"
|
||||||
|
llvm_gcc.options.always = "-w"
|
||||||
|
llvm_gcc.options.speed = "-O2"
|
||||||
|
llvm_gcc.options.size = "-Os"
|
||||||
|
|
||||||
|
# Configuration for the LLVM CLang compiler:
|
||||||
|
clang.options.debug = "-g"
|
||||||
|
clang.options.always = "-w"
|
||||||
|
clang.options.speed = "-O3"
|
||||||
|
clang.options.size = "-Os"
|
||||||
|
|
||||||
|
# Configuration for the Visual C/C++ compiler:
|
||||||
|
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
||||||
|
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||||
|
vcc.options.always = "/nologo"
|
||||||
|
vcc.options.speed = "/Ox /arch:SSE2"
|
||||||
|
vcc.options.size = "/O1"
|
||||||
|
|
||||||
|
# Configuration for the Digital Mars C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
dmc.path = r"$nimrod\dist\dm\bin"
|
||||||
|
@end
|
||||||
|
|
||||||
|
# Configuration for the Tiny C Compiler:
|
||||||
|
tcc.options.always = "-w"
|
||||||
|
|
@ -130,10 +130,5 @@ vcc.options.always = "/nologo"
|
||||||
vcc.options.speed = "/Ox /arch:SSE2"
|
vcc.options.speed = "/Ox /arch:SSE2"
|
||||||
vcc.options.size = "/O1"
|
vcc.options.size = "/O1"
|
||||||
|
|
||||||
# Configuration for the Digital Mars C/C++ compiler:
|
|
||||||
@if windows:
|
|
||||||
dmc.path = r"$nimrod\dist\dm\bin"
|
|
||||||
@end
|
|
||||||
|
|
||||||
# Configuration for the Tiny C Compiler:
|
# Configuration for the Tiny C Compiler:
|
||||||
tcc.options.always = "-w"
|
tcc.options.always = "-w"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
===============================================================================
|
=====================================================
|
||||||
Nimrod -- a Compiler for Nimrod. http://nimrod-code.org/
|
Nimrod -- a Compiler for Nimrod. http://nimrod-lang.org/
|
||||||
|
|
||||||
Copyright (C) 2004-2014 Andreas Rumpf. All rights reserved.
|
Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Advanced commands:
|
||||||
module dependency graph
|
module dependency graph
|
||||||
//dump dump all defined conditionals and search paths
|
//dump dump all defined conditionals and search paths
|
||||||
//check checks the project for syntax and semantic
|
//check checks the project for syntax and semantic
|
||||||
|
//pretty homogenizes source code style
|
||||||
//idetools compiler support for IDEs: possible options:
|
//idetools compiler support for IDEs: possible options:
|
||||||
--track:FILE,LINE,COL track a file/cursor position
|
--track:FILE,LINE,COL track a file/cursor position
|
||||||
--trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL
|
--trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,64 @@ earlier, JavaScript doesn't require an initialisation call to ``NimMain`` or
|
||||||
similar function and you can call the exported Nimrod proc directly.
|
similar function and you can call the exported Nimrod proc directly.
|
||||||
|
|
||||||
|
|
||||||
|
Nimcache naming logic
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The `nimcache`:idx: directory is generated during compilation and will hold
|
||||||
|
either temporary or final files depending on your backend target. The default
|
||||||
|
name for the directory is ``nimcache`` but you can use the ``--nimcache``
|
||||||
|
`compiler switch <nimrodc.html#command-line-switches>`_ to change it.
|
||||||
|
|
||||||
|
Nimcache and C like targets
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The C like backends will place their temporary ``.c``, ``.cpp`` or ``.m`` files
|
||||||
|
in the ``nimcache`` directory. The naming of these files follows the pattern
|
||||||
|
``babelPackageName_`` + ``nimrodSource``:
|
||||||
|
|
||||||
|
* Filenames for modules imported from `Babel packages
|
||||||
|
<https://github.com/nimrod-code/babel>`_ will end up with
|
||||||
|
``babelPackageName_module.c``. For example, if you import the
|
||||||
|
``argument_parser`` module from the same name Babel package you
|
||||||
|
will end up with a ``argument_parser_argument_parser.c`` file
|
||||||
|
under ``nimcache``. The name of the Babel package comes from the
|
||||||
|
``proj.babel`` file, the actual contents are not read by the
|
||||||
|
compiler.
|
||||||
|
|
||||||
|
* Filenames for non babel packages (like your project) will be
|
||||||
|
renamed from ``.nim`` to have the extension of your target backend
|
||||||
|
(from now on ``.c`` for these examples), but otherwise nothing
|
||||||
|
else will change. This will quickly break if your project consists
|
||||||
|
of a main ``proj.nim`` file which includes a ``utils/proj.nim``
|
||||||
|
file: both ``proj.nim`` files will generate the same name ``proj.c``
|
||||||
|
output in the ``nimcache`` directory overwriting themselves!
|
||||||
|
|
||||||
|
* Filenames for modules found in the standard library will be named
|
||||||
|
``stdlib_module.c``. Unless you are doing something special, you
|
||||||
|
will end up with at least ``stdlib_system.c``, since the `system
|
||||||
|
module <system.html>`_ is always imported automatically. Same for
|
||||||
|
the `hashes module <hashes.html>`_ which will be named
|
||||||
|
``stdlib_hashes.c``. The ``stdlib_`` prefix comes from the *fake*
|
||||||
|
``lib/stdlib.babel`` file.
|
||||||
|
|
||||||
|
To find the name of a Babel package the compiler searches for a ``*.babel``
|
||||||
|
file in the parent directory hierarchy of whatever module you are compiling.
|
||||||
|
Even if you are in a subdirectory of your project, a parent ``*.babel`` file
|
||||||
|
will influence the naming of the nimcache name. This means that on Unix systems
|
||||||
|
creating the file ``~/foo.babel`` will automatically prefix all nimcache files
|
||||||
|
not part of another package with the string ``foo_``.
|
||||||
|
|
||||||
|
|
||||||
|
Nimcache and the Javascript target
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Unless you explicitly use the ``-o:filename.js`` switch as mentioned in the
|
||||||
|
previous examples, the compiler will create a ``filename.js`` file in the
|
||||||
|
``nimcache`` directory using the name of your input nimrod file. There are no
|
||||||
|
other temporary files generated, the output is always a single self contained
|
||||||
|
``.js`` file.
|
||||||
|
|
||||||
|
|
||||||
Memory management
|
Memory management
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ Options:
|
||||||
-p, --path:PATH add path to search paths
|
-p, --path:PATH add path to search paths
|
||||||
-d, --define:SYMBOL define a conditional symbol
|
-d, --define:SYMBOL define a conditional symbol
|
||||||
-u, --undef:SYMBOL undefine a conditional symbol
|
-u, --undef:SYMBOL undefine a conditional symbol
|
||||||
|
--symbol:SYMBOL declare a conditional symbol
|
||||||
-f, --forceBuild force rebuilding of all modules
|
-f, --forceBuild force rebuilding of all modules
|
||||||
--stackTrace:on|off turn stack tracing on|off
|
--stackTrace:on|off turn stack tracing on|off
|
||||||
--lineTrace:on|off turn line tracing on|off
|
--lineTrace:on|off turn line tracing on|off
|
||||||
|
|
@ -34,3 +35,5 @@ Options:
|
||||||
-r, --run run the compiled program with given arguments
|
-r, --run run the compiled program with given arguments
|
||||||
--advanced show advanced command line switches
|
--advanced show advanced command line switches
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
|
|
||||||
|
Note: Even single letter options require the colon: -p:PATH.
|
||||||
|
|
|
||||||
295
doc/c2nim.txt
295
doc/c2nim.txt
|
|
@ -1,295 +0,0 @@
|
||||||
=======================
|
|
||||||
c2nim User's manual
|
|
||||||
=======================
|
|
||||||
|
|
||||||
:Author: Andreas Rumpf
|
|
||||||
:Version: |nimrodversion|
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
============
|
|
||||||
|
|
||||||
"We all make choices. But in the end our choices make us."
|
|
||||||
|
|
||||||
|
|
||||||
c2nim is a tool to translate Ansi C code to Nimrod. The output is
|
|
||||||
human-readable Nimrod code that is meant to be tweaked by hand after the
|
|
||||||
translation process. c2nim is no real compiler!
|
|
||||||
|
|
||||||
c2nim is preliminary meant to translate C header files. Because of this, the
|
|
||||||
preprocessor is part of the parser. For example:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#define abc 123
|
|
||||||
#define xyz 789
|
|
||||||
|
|
||||||
Is translated into:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
const
|
|
||||||
abc* = 123
|
|
||||||
xyz* = 789
|
|
||||||
|
|
||||||
|
|
||||||
c2nim is meant to translate fragments of C code and thus does not follow
|
|
||||||
include files. c2nim cannot parse all of Ansi C and many constructs cannot
|
|
||||||
be represented in Nimrod: for example `duff's device`:idx: cannot be translated
|
|
||||||
to Nimrod.
|
|
||||||
|
|
||||||
|
|
||||||
Preprocessor support
|
|
||||||
====================
|
|
||||||
|
|
||||||
Even though the translation process is not perfect, it is often the case that
|
|
||||||
the translated Nimrod code does not need any tweaking by hand. In other cases
|
|
||||||
it may be preferable to modify the input file instead of the generated Nimrod
|
|
||||||
code so that c2nim can parse it properly. c2nim's preprocessor defines the
|
|
||||||
symbol ``C2NIM`` that can be used to mark code sections:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#ifndef C2NIM
|
|
||||||
// C2NIM should ignore this prototype:
|
|
||||||
int fprintf(FILE* f, const char* frmt, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
The ``C2NIM`` symbol is only recognized in ``#ifdef`` and ``#ifndef``
|
|
||||||
constructs! ``#if defined(C2NIM)`` does **not** work.
|
|
||||||
|
|
||||||
c2nim *processes* ``#ifdef C2NIM`` and ``#ifndef C2NIM`` directives, but other
|
|
||||||
``#if[def]`` directives are *translated* into Nimrod's ``when`` construct:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define OUT(x) printf("%s\n", x)
|
|
||||||
#else
|
|
||||||
# define OUT(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Is translated into:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
when defined(debug):
|
|
||||||
template OUT*(x: expr): expr =
|
|
||||||
printf("%s\x0A", x)
|
|
||||||
else:
|
|
||||||
template OUT*(x: expr): stmt =
|
|
||||||
discard
|
|
||||||
|
|
||||||
As can been seen from the example, C's macros with parameters are mapped
|
|
||||||
to Nimrod's templates. This mapping is the best one can do, but it is of course
|
|
||||||
not accurate: Nimrod's templates operate on syntax trees whereas C's
|
|
||||||
macros work on the token level. c2nim cannot translate any macro that contains
|
|
||||||
the ``##`` token concatenation operator.
|
|
||||||
|
|
||||||
c2nim's preprocessor supports special directives that affect how the output
|
|
||||||
is generated. They should be put into a ``#ifdef C2NIM`` section so that
|
|
||||||
ordinary C compilers ignore them.
|
|
||||||
|
|
||||||
|
|
||||||
``#skipinclude`` directive
|
|
||||||
--------------------------
|
|
||||||
**Note**: There is also a ``--skipinclude`` command line option that can be
|
|
||||||
used for the same purpose.
|
|
||||||
|
|
||||||
By default, c2nim translates an ``#include`` that is not followed by ``<``
|
|
||||||
(like in ``#include <stdlib>``) to a Nimrod ``import`` statement. This
|
|
||||||
directive tells c2nim to just skip any ``#include``.
|
|
||||||
|
|
||||||
|
|
||||||
``#stdcall`` and ``#cdecl`` directives
|
|
||||||
--------------------------------------
|
|
||||||
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
|
|
||||||
that can be used for the same purpose.
|
|
||||||
|
|
||||||
These directives tell c2nim that it should annotate every proc (or proc type)
|
|
||||||
with the ``stdcall`` / ``cdecl`` calling convention.
|
|
||||||
|
|
||||||
|
|
||||||
``#dynlib`` directive
|
|
||||||
---------------------
|
|
||||||
**Note**: There is also a ``--dynlib`` command line option that can be used for
|
|
||||||
the same purpose.
|
|
||||||
|
|
||||||
This directive tells c2nim that it should annotate every proc that resulted
|
|
||||||
from a C function prototype with the ``dynlib`` pragma:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# dynlib iupdll
|
|
||||||
# cdecl
|
|
||||||
# if defined(windows)
|
|
||||||
# define iupdll "iup.dll"
|
|
||||||
# elif defined(macosx)
|
|
||||||
# define iupdll "libiup.dylib"
|
|
||||||
# else
|
|
||||||
# define iupdll "libiup.so"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
|
||||||
|
|
||||||
Is translated to:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
when defined(windows):
|
|
||||||
const iupdll* = "iup.dll"
|
|
||||||
elif defined(macosx):
|
|
||||||
const iupdll* = "libiup.dylib"
|
|
||||||
else:
|
|
||||||
const iupdll* = "libiup.so"
|
|
||||||
|
|
||||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
|
||||||
importc: "IupConvertXYToPos", cdecl, dynlib: iupdll.}
|
|
||||||
|
|
||||||
Note how the example contains extra C code to declare the ``iupdll`` symbol
|
|
||||||
in the generated Nimrod code.
|
|
||||||
|
|
||||||
|
|
||||||
``#header`` directive
|
|
||||||
---------------------
|
|
||||||
**Note**: There is also a ``--header`` command line option that can be used for
|
|
||||||
the same purpose.
|
|
||||||
|
|
||||||
The ``#header`` directive tells c2nim that it should annotate every proc that
|
|
||||||
resulted from a C function prototype and every exported variable and type with
|
|
||||||
the ``header`` pragma:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# header "iup.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
|
||||||
|
|
||||||
Is translated to:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
|
||||||
importc: "IupConvertXYToPos", header: "iup.h".}
|
|
||||||
|
|
||||||
The ``#header`` and the ``#dynlib`` directives are mutually exclusive.
|
|
||||||
A binding that uses ``dynlib`` is much more preferable over one that uses
|
|
||||||
``header``! The Nimrod compiler might drop support for the ``header`` pragma
|
|
||||||
in the future as it cannot work for backends that do not generate C code.
|
|
||||||
|
|
||||||
|
|
||||||
``#prefix`` and ``#suffix`` directives
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
**Note**: There are also ``--prefix`` and ``--suffix`` command line options
|
|
||||||
that can be used for the same purpose.
|
|
||||||
|
|
||||||
c2nim does not do any name mangling by default. However the
|
|
||||||
``#prefix`` and ``#suffix`` directives can be used to strip prefixes and
|
|
||||||
suffixes from the identifiers in the C code:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
|
|
||||||
#ifdef C2NIM
|
|
||||||
# prefix Iup
|
|
||||||
# dynlib dllname
|
|
||||||
# cdecl
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
|
||||||
|
|
||||||
Is translated to:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
|
|
||||||
proc ConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
|
||||||
importc: "IupConvertXYToPos", cdecl, dynlib: dllname.}
|
|
||||||
|
|
||||||
|
|
||||||
``#mangle`` directive
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
Even more sophisticated name mangling can be achieved by the ``#mangle``
|
|
||||||
directive: It takes a PEG pattern and format string that specify how the
|
|
||||||
identifier should be converted:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#mangle "'GTK_'{.*}" "TGtk$1"
|
|
||||||
|
|
||||||
For convenience the PEG pattern and the replacement can be single identifiers
|
|
||||||
too, there is no need to quote them:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#mangle ssize_t int
|
|
||||||
// is short for:
|
|
||||||
#mangle "'ssize_t'" "int"
|
|
||||||
|
|
||||||
|
|
||||||
``#private`` directive
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
By default c2nim marks every top level identifier (proc name, variable, etc.)
|
|
||||||
as exported (the export marker is ``*`` in Nimrod). With the ``#private``
|
|
||||||
directive identifiers can be marked as private so that the resulting Nimrod
|
|
||||||
module does not export them. The ``#private`` directive takes a PEG pattern:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#private "@('_'!.)" // all identifiers ending in '_' are private
|
|
||||||
|
|
||||||
Note: The pattern refers to the original C identifiers, not to the resulting
|
|
||||||
identifiers after mangling!
|
|
||||||
|
|
||||||
|
|
||||||
``#skipcomments`` directive
|
|
||||||
---------------------------
|
|
||||||
**Note**: There is also a ``--skipcomments`` command line option that can be
|
|
||||||
used for the same purpose.
|
|
||||||
|
|
||||||
The ``#skipcomments`` directive can be put into the C code to make c2nim
|
|
||||||
ignore comments and not copy them into the generated Nimrod file.
|
|
||||||
|
|
||||||
|
|
||||||
``#typeprefixes`` directive
|
|
||||||
---------------------------
|
|
||||||
**Note**: There is also a ``--typeprefixes`` command line option that can be
|
|
||||||
used for the same purpose.
|
|
||||||
|
|
||||||
The ``#typeprefixes`` directive can be put into the C code to make c2nim
|
|
||||||
generate the ``T`` or ``P`` prefix for every defined type.
|
|
||||||
|
|
||||||
|
|
||||||
``#def`` directive
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Often C code contains special macros that affect the declaration of a function
|
|
||||||
prototype but confuse c2nim's parser:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
// does not parse!
|
|
||||||
EXTERN(int) f(void);
|
|
||||||
EXTERN(int) g(void);
|
|
||||||
|
|
||||||
Instead of removing ``EXTERN()`` from the input source file (which cannot be
|
|
||||||
done reliably even with a regular expression!), one can tell c2nim
|
|
||||||
that ``EXPORT`` is a macro that should be expanded by c2nim too:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
#ifdef C2NIM
|
|
||||||
# def EXTERN(x) static x
|
|
||||||
#endif
|
|
||||||
// parses now!
|
|
||||||
EXTERN(int) f(void);
|
|
||||||
EXTERN(int) g(void);
|
|
||||||
|
|
||||||
``#def`` is very similar to C's ``#define``, so in general the macro definition
|
|
||||||
can be copied and pasted into a ``#def`` directive.
|
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
|
||||||
===========
|
|
||||||
|
|
||||||
* C's ``,`` operator (comma operator) is not supported.
|
|
||||||
* C's ``union`` are translated to Nimrod's objects and only the first field
|
|
||||||
is included in the object type. This way there is a high chance that it is
|
|
||||||
binary compatible to the union.
|
|
||||||
* The condition in a ``do while(condition)`` statement must be ``0``.
|
|
||||||
* Lots of other small issues...
|
|
||||||
|
|
||||||
31
doc/exception_hierarchy_fragment.txt
Normal file
31
doc/exception_hierarchy_fragment.txt
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
* `E_Base <system.html#E_Base>`_
|
||||||
|
* `EAccessViolation <system.html#EAccessViolation>`_
|
||||||
|
* `EArithmetic <system.html#EArithmetic>`_
|
||||||
|
* `EDivByZero <system.html#EDivByZero>`_
|
||||||
|
* `EOverflow <system.html#EOverflow>`_
|
||||||
|
* `EAssertionFailed <system.html#EAssertionFailed>`_
|
||||||
|
* `EAsynch <system.html#EAsynch>`_
|
||||||
|
* `EControlC <system.html#EControlC>`_
|
||||||
|
* `EDeadThread <system.html#EDeadThread>`_
|
||||||
|
* `EFloatingPoint <system.html#EFloatingPoint>`_
|
||||||
|
* `EFloatDivByZero <system.html#EFloatDivByZero>`_
|
||||||
|
* `EFloatInexact <system.html#EFloatInexact>`_
|
||||||
|
* `EFloatInvalidOp <system.html#EFloatInvalidOp>`_
|
||||||
|
* `EFloatOverflow <system.html#EFloatOverflow>`_
|
||||||
|
* `EFloatUnderflow <system.html#EFloatUnderflow>`_
|
||||||
|
* `EInvalidField <system.html#EInvalidField>`_
|
||||||
|
* `EInvalidIndex <system.html#EInvalidIndex>`_
|
||||||
|
* `EInvalidObjectAssignment <system.html#EInvalidObjectAssignment>`_
|
||||||
|
* `EInvalidObjectConversion <system.html#EInvalidObjectConversion>`_
|
||||||
|
* `EInvalidValue <system.html#EInvalidValue>`_
|
||||||
|
* `EInvalidKey <system.html#EInvalidKey>`_
|
||||||
|
* `ENoExceptionToReraise <system.html#ENoExceptionToReraise>`_
|
||||||
|
* `EOutOfRange <system.html#EOutOfRange>`_
|
||||||
|
* `ESynch <system.html#ESynch>`_
|
||||||
|
* `EOutOfMemory <system.html#EOutOfMemory>`_
|
||||||
|
* `EResourceExhausted <system.html#EResourceExhausted>`_
|
||||||
|
* `EStackOverflow <system.html#EStackOverflow>`_
|
||||||
|
* `ESystem <system.html#ESystem>`_
|
||||||
|
* `EIO <system.html#EIO>`_
|
||||||
|
* `EOS <system.html#EOS>`_
|
||||||
|
* `EInvalidLibrary <system.html#EInvalidLibrary>`_
|
||||||
|
|
@ -6,7 +6,7 @@ elif else end enum except export
|
||||||
finally for from
|
finally for from
|
||||||
generic
|
generic
|
||||||
if import in include interface is isnot iterator
|
if import in include interface is isnot iterator
|
||||||
lambda let
|
let
|
||||||
macro method mixin mod
|
macro method mixin mod
|
||||||
nil not notin
|
nil not notin
|
||||||
object of or out
|
object of or out
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,13 @@ from rst to HTML. It also repeats the same operation but places the result in
|
||||||
the ``web/upload`` which can be used to update the website at
|
the ``web/upload`` which can be used to update the website at
|
||||||
http://nimrod-lang.org.
|
http://nimrod-lang.org.
|
||||||
|
|
||||||
|
By default the documentation will be built in parallel using the number of
|
||||||
|
available CPU cores. If any documentation build sub commands fail, they will
|
||||||
|
be rerun in serial fashion so that meaninful error output can be gathered for
|
||||||
|
inspection. The ``--parallelBuild:n`` switch or configuration option can be
|
||||||
|
used to force a specific number of parallel jobs or run everything serially
|
||||||
|
from the start (``n == 1``).
|
||||||
|
|
||||||
zip command
|
zip command
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
|
||||||
15
doc/lib.txt
15
doc/lib.txt
|
|
@ -57,6 +57,9 @@ Core
|
||||||
* `typeinfo <typeinfo.html>`_
|
* `typeinfo <typeinfo.html>`_
|
||||||
Provides (unsafe) access to Nimrod's run time type information.
|
Provides (unsafe) access to Nimrod's run time type information.
|
||||||
|
|
||||||
|
* `typetraits <typetraits.html>`_
|
||||||
|
This module defines compile-time reflection procs for working with types.
|
||||||
|
|
||||||
* `actors <actors.html>`_
|
* `actors <actors.html>`_
|
||||||
Actor support for Nimrod; implemented as a layer on top of the threads and
|
Actor support for Nimrod; implemented as a layer on top of the threads and
|
||||||
channels modules.
|
channels modules.
|
||||||
|
|
@ -447,10 +450,6 @@ Other
|
||||||
This module contains code for reading from `stdin`:idx:. On UNIX the GNU
|
This module contains code for reading from `stdin`:idx:. On UNIX the GNU
|
||||||
readline library is wrapped and set up.
|
readline library is wrapped and set up.
|
||||||
|
|
||||||
* `zmq <zmq.html>`_
|
|
||||||
Nimrod 0mq wrapper. This file contains the low level C wrappers as well as
|
|
||||||
some higher level constructs.
|
|
||||||
|
|
||||||
|
|
||||||
Wrappers
|
Wrappers
|
||||||
========
|
========
|
||||||
|
|
@ -463,8 +462,6 @@ Windows specific
|
||||||
|
|
||||||
* `windows <windows.html>`_
|
* `windows <windows.html>`_
|
||||||
Contains a wrapper for the Win32 API.
|
Contains a wrapper for the Win32 API.
|
||||||
* `ole2 <ole2.html>`_
|
|
||||||
Contains GUIDs for OLE2 automation support.
|
|
||||||
* `shellapi <shellapi.html>`_
|
* `shellapi <shellapi.html>`_
|
||||||
Contains a wrapper for the ``shellapi.h`` header.
|
Contains a wrapper for the ``shellapi.h`` header.
|
||||||
* `shfolder <shfolder.html>`_
|
* `shfolder <shfolder.html>`_
|
||||||
|
|
@ -594,7 +591,8 @@ compiler.
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<div id="officialPkgList"></div>
|
<div id="officialPkgList"><b>If you are reading this you are missing
|
||||||
|
babelpkglist.js or have javascript disabled in your browser.</b></div>
|
||||||
|
|
||||||
Unofficial packages
|
Unofficial packages
|
||||||
-------------------
|
-------------------
|
||||||
|
|
@ -605,7 +603,8 @@ Nimrod programming language.
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<div id="unofficialPkgList"></div>
|
<div id="unofficialPkgList"><b>If you are reading this you are missing
|
||||||
|
babelpkglist.js or have javascript disabled in your browser.</b></div>
|
||||||
|
|
||||||
<script type="text/javascript" src="babelpkglist.js"></script>
|
<script type="text/javascript" src="babelpkglist.js"></script>
|
||||||
<script type="text/javascript" src="http://build.nimrod-lang.org/packages?callback=gotPackageList"></script>
|
<script type="text/javascript" src="http://build.nimrod-lang.org/packages?callback=gotPackageList"></script>
|
||||||
|
|
|
||||||
254
doc/manual.txt
254
doc/manual.txt
|
|
@ -1221,38 +1221,8 @@ branch switch ``system.reset`` has to be used.
|
||||||
|
|
||||||
Set type
|
Set type
|
||||||
--------
|
--------
|
||||||
The set type models the mathematical notion of a set. The set's
|
|
||||||
basetype can only be an ordinal type. The reason is that sets are implemented
|
|
||||||
as high performance bit vectors.
|
|
||||||
|
|
||||||
Sets can be constructed via the set constructor: ``{}`` is the empty set. The
|
|
||||||
empty set is type compatible with any special set type. The constructor
|
|
||||||
can also be used to include elements (and ranges of elements) in the set:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
|
||||||
|
|
||||||
{'a'..'z', '0'..'9'} # This constructs a set that contains the
|
|
||||||
# letters from 'a' to 'z' and the digits
|
|
||||||
# from '0' to '9'
|
|
||||||
|
|
||||||
These operations are supported by sets:
|
|
||||||
|
|
||||||
================== ========================================================
|
|
||||||
operation meaning
|
|
||||||
================== ========================================================
|
|
||||||
``A + B`` union of two sets
|
|
||||||
``A * B`` intersection of two sets
|
|
||||||
``A - B`` difference of two sets (A without B's elements)
|
|
||||||
``A == B`` set equality
|
|
||||||
``A <= B`` subset relation (A is subset of B or equal to B)
|
|
||||||
``A < B`` strong subset relation (A is a real subset of B)
|
|
||||||
``e in A`` set membership (A contains element e)
|
|
||||||
``A -+- B`` symmetric set difference (= (A - B) + (B - A))
|
|
||||||
``card(A)`` the cardinality of A (number of elements in A)
|
|
||||||
``incl(A, elem)`` same as A = A + {elem}
|
|
||||||
``excl(A, elem)`` same as A = A - {elem}
|
|
||||||
================== ========================================================
|
|
||||||
|
|
||||||
|
.. include:: sets_fragment.txt
|
||||||
|
|
||||||
Reference and pointer types
|
Reference and pointer types
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
@ -1451,7 +1421,7 @@ Examples:
|
||||||
proc forEach(c: proc (x: int) {.cdecl.}) =
|
proc forEach(c: proc (x: int) {.cdecl.}) =
|
||||||
...
|
...
|
||||||
|
|
||||||
forEach(printItem) # this will NOT work because calling conventions differ
|
forEach(printItem) # this will NOT compile because calling conventions differ
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -2497,7 +2467,7 @@ variable to use:
|
||||||
|
|
||||||
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
|
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
|
||||||
be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
|
be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
|
||||||
is ambiguous)``. To solve this you would need to nest ``using`` with a
|
is ambiguous)``. To solve this one would need to nest ``using`` with a
|
||||||
``block`` statement so as to control the reach of the ``using`` statement.
|
``block`` statement so as to control the reach of the ``using`` statement.
|
||||||
|
|
||||||
If expression
|
If expression
|
||||||
|
|
@ -4347,7 +4317,7 @@ Nimrod offers a special family of dot operators that can be used to
|
||||||
intercept and rewrite proc call and field access attempts, referring
|
intercept and rewrite proc call and field access attempts, referring
|
||||||
to previously undeclared symbol names. They can be used to provide a
|
to previously undeclared symbol names. They can be used to provide a
|
||||||
fluent interface to objects lying outside the static confines of the
|
fluent interface to objects lying outside the static confines of the
|
||||||
Nimrod's type system such as values from dynamic scripting languages
|
type system such as values from dynamic scripting languages
|
||||||
or dynamic file formats such as JSON or XML.
|
or dynamic file formats such as JSON or XML.
|
||||||
|
|
||||||
When Nimrod encounters an expression that cannot be resolved by the
|
When Nimrod encounters an expression that cannot be resolved by the
|
||||||
|
|
@ -4379,8 +4349,8 @@ This operator will be matched against both field accesses and method calls.
|
||||||
operator `.()`
|
operator `.()`
|
||||||
---------------
|
---------------
|
||||||
This operator will be matched exclusively against method calls. It has higher
|
This operator will be matched exclusively against method calls. It has higher
|
||||||
precedence than the `.` operator and this allows you to handle expressions like
|
precedence than the `.` operator and this allows one to handle expressions like
|
||||||
`x.y` and `x.y()` differently if you are interfacing with a scripting language
|
`x.y` and `x.y()` differently if one is interfacing with a scripting language
|
||||||
for example.
|
for example.
|
||||||
|
|
||||||
operator `.=`
|
operator `.=`
|
||||||
|
|
@ -4391,6 +4361,117 @@ This operator will be matched against assignments to missing fields.
|
||||||
a.b = c # becomes `.=`(a, "b", c)
|
a.b = c # becomes `.=`(a, "b", c)
|
||||||
|
|
||||||
|
|
||||||
|
Type bound operations
|
||||||
|
=====================
|
||||||
|
|
||||||
|
There are 3 operations that are bound to a type:
|
||||||
|
|
||||||
|
1. Assignment
|
||||||
|
2. Destruction
|
||||||
|
3. Deep copying for communication between threads
|
||||||
|
|
||||||
|
These operations can be *overriden* instead of *overloaded*. This means the
|
||||||
|
implementation is automatically lifted to structured types. For instance if type
|
||||||
|
``T`` has an overriden assignment operator ``=`` this operator is also used
|
||||||
|
for assignments of the type ``seq[T]``. Since these operations are bound to a
|
||||||
|
type they have to be bound to a nominal type for reasons of simplicity of
|
||||||
|
implementation: This means an overriden ``deepCopy`` for ``ref T`` is really
|
||||||
|
bound to ``T`` and not to ``ref T``. This also means that one cannot override
|
||||||
|
``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a
|
||||||
|
helper distinct or object type has to be used for one pointer type.
|
||||||
|
|
||||||
|
|
||||||
|
operator `=`
|
||||||
|
------------
|
||||||
|
|
||||||
|
**Note**: Overriding the assignment operator has not yet been implemented.
|
||||||
|
|
||||||
|
This operator is the assignment operator. Note that in the contexts
|
||||||
|
like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for
|
||||||
|
parameter passing no assignment is performed. The ``override`` pragma is
|
||||||
|
optional for overriding ``=``.
|
||||||
|
|
||||||
|
|
||||||
|
destructors
|
||||||
|
-----------
|
||||||
|
|
||||||
|
A destructor must have a single parameter with a concrete type (the name of a
|
||||||
|
generic type is allowed too). The name of the destructor has to be ``destroy``
|
||||||
|
and it need to be annotated with the ``override`` pragma.
|
||||||
|
|
||||||
|
``destroy(v)`` will be automatically invoked for every local stack
|
||||||
|
variable ``v`` that goes out of scope.
|
||||||
|
|
||||||
|
If a structured type features a field with destructable type and
|
||||||
|
the user has not provided an explicit implementation, a destructor for the
|
||||||
|
structured type will be automatically generated. Calls to any base class
|
||||||
|
destructors in both user-defined and generated destructors will be inserted.
|
||||||
|
|
||||||
|
A destructor is attached to the type it destructs; expressions of this type
|
||||||
|
can then only be used in *destructible contexts* and as parameters:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
TMyObj = object
|
||||||
|
x, y: int
|
||||||
|
p: pointer
|
||||||
|
|
||||||
|
proc destroy(o: var TMyObj) {.override.} =
|
||||||
|
if o.p != nil: dealloc o.p
|
||||||
|
|
||||||
|
proc open: TMyObj =
|
||||||
|
result = TMyObj(x: 1, y: 2, p: alloc(3))
|
||||||
|
|
||||||
|
proc work(o: TMyObj) =
|
||||||
|
echo o.x
|
||||||
|
# No destructor invoked here for 'o' as 'o' is a parameter.
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
# destructor automatically invoked at the end of the scope:
|
||||||
|
var x = open()
|
||||||
|
# valid: pass 'x' to some other proc:
|
||||||
|
work(x)
|
||||||
|
|
||||||
|
# Error: usage of a type with a destructor in a non destructible context
|
||||||
|
echo open()
|
||||||
|
|
||||||
|
A destructible context is currently only the following:
|
||||||
|
|
||||||
|
1. The ``expr`` in ``var x = expr``.
|
||||||
|
2. The ``expr`` in ``let x = expr``.
|
||||||
|
3. The ``expr`` in ``return expr``.
|
||||||
|
4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol
|
||||||
|
introduced by the compiler.
|
||||||
|
|
||||||
|
These rules ensure that the construction is tied to a variable and can easily
|
||||||
|
be destructed at its scope exit. Later versions of the language will improve
|
||||||
|
the support of destructors.
|
||||||
|
|
||||||
|
Be aware that destructors are not called for objects allocated with ``new``.
|
||||||
|
This may change in future versions of language, but for now the ``finalizer``
|
||||||
|
parameter to ``new`` has to be used.
|
||||||
|
|
||||||
|
|
||||||
|
deepCopy
|
||||||
|
--------
|
||||||
|
|
||||||
|
``deepCopy`` is a builtin that is invoked whenever data is passed to
|
||||||
|
a ``spawn``'ed proc to ensure memory safety. The programmer can override its
|
||||||
|
behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
|
||||||
|
language may weaken this restriction.)
|
||||||
|
|
||||||
|
The signature has to be:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc deepCopy(x: T): T {.override.}
|
||||||
|
|
||||||
|
This mechanism is used by most data structures that support shared memory like
|
||||||
|
channels to implement thread safe automatic memory management.
|
||||||
|
|
||||||
|
The builtin ``deepCopy`` can even clone closures and their environments. See
|
||||||
|
the documentation of `spawn`_ for details.
|
||||||
|
|
||||||
|
|
||||||
Term rewriting macros
|
Term rewriting macros
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|
@ -4960,6 +5041,27 @@ first implementation to play with a language feature before a nicer syntax
|
||||||
to access the feature becomes available.
|
to access the feature becomes available.
|
||||||
|
|
||||||
|
|
||||||
|
deprecated pragma
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The deprecated pragma is used to mark a symbol as deprecated:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc p() {.deprecated.}
|
||||||
|
var x {.deprecated.}: char
|
||||||
|
|
||||||
|
It can also be used as a statement. Then it takes a list of *renamings*. The
|
||||||
|
upcoming ``nimfix`` tool can automatically update the code and perform these
|
||||||
|
renamings:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
File = object
|
||||||
|
Stream = ref object
|
||||||
|
{.deprecated: [TFile: File, PStream: Stream].}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
noSideEffect pragma
|
noSideEffect pragma
|
||||||
-------------------
|
-------------------
|
||||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||||
|
|
@ -4970,9 +5072,9 @@ or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||||
verify this.
|
verify this.
|
||||||
|
|
||||||
As a special semantic rule, the built-in ``debugEcho`` pretends to be free of
|
As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
|
||||||
side effects, so that it can be used for debugging routines marked as
|
pretends to be free of side effects, so that it can be used for debugging
|
||||||
``noSideEffect``.
|
routines marked as ``noSideEffect``.
|
||||||
|
|
||||||
**Future directions**: ``func`` may become a keyword and syntactic sugar for a
|
**Future directions**: ``func`` may become a keyword and syntactic sugar for a
|
||||||
proc with no side effects:
|
proc with no side effects:
|
||||||
|
|
@ -4985,62 +5087,14 @@ destructor pragma
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The ``destructor`` pragma is used to mark a proc to act as a type destructor.
|
The ``destructor`` pragma is used to mark a proc to act as a type destructor.
|
||||||
The proc must have a single parameter with a concrete type (the name of a
|
Its usage is deprecated, use the ``override`` pragma instead.
|
||||||
generic type is allowed too).
|
See `type bound operations`_.
|
||||||
|
|
||||||
Destructors will be automatically invoked when a local stack variable goes
|
|
||||||
out of scope.
|
|
||||||
|
|
||||||
If a record type features a field with destructable type and
|
override pragma
|
||||||
the user have not provided explicit implementation, Nimrod will automatically
|
---------------
|
||||||
generate a destructor for the record type. Nimrod will automatically insert
|
|
||||||
calls to any base class destructors in both user-defined and generated
|
|
||||||
destructors.
|
|
||||||
|
|
||||||
A destructor is attached to the type it destructs; expressions of this type
|
|
||||||
can then only be used in *destructible contexts* and as parameters:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
|
||||||
type
|
|
||||||
TMyObj = object
|
|
||||||
x, y: int
|
|
||||||
p: pointer
|
|
||||||
|
|
||||||
proc destruct(o: var TMyObj) {.destructor.} =
|
|
||||||
if o.p != nil: dealloc o.p
|
|
||||||
|
|
||||||
proc open: TMyObj =
|
|
||||||
result = TMyObj(x: 1, y: 2, p: alloc(3))
|
|
||||||
|
|
||||||
proc work(o: TMyObj) =
|
|
||||||
echo o.x
|
|
||||||
# No destructor invoked here for 'o' as 'o' is a parameter.
|
|
||||||
|
|
||||||
proc main() =
|
|
||||||
# destructor automatically invoked at the end of the scope:
|
|
||||||
var x = open()
|
|
||||||
# valid: pass 'x' to some other proc:
|
|
||||||
work(x)
|
|
||||||
|
|
||||||
# Error: usage of a type with a destructor in a non destructible context
|
|
||||||
echo open()
|
|
||||||
|
|
||||||
A destructible context is currently only the following:
|
|
||||||
|
|
||||||
1. The ``expr`` in ``var x = expr``.
|
|
||||||
2. The ``expr`` in ``let x = expr``.
|
|
||||||
3. The ``expr`` in ``return expr``.
|
|
||||||
4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol
|
|
||||||
introduced by the compiler.
|
|
||||||
|
|
||||||
These rules ensure that the construction is tied to a variable and can easily
|
|
||||||
be destructed at its scope exit. Later versions of the language will improve
|
|
||||||
the support of destructors.
|
|
||||||
|
|
||||||
Be aware that destructors are not called for objects allocated with ``new``.
|
|
||||||
This may change in future versions of language, but for now use
|
|
||||||
the ``finalizer`` parameter to ``new``.
|
|
||||||
|
|
||||||
|
See `type bound operations`_ instead.
|
||||||
|
|
||||||
procvar pragma
|
procvar pragma
|
||||||
--------------
|
--------------
|
||||||
|
|
@ -5290,7 +5344,7 @@ See `Ordinary vs immediate templates`_.
|
||||||
compilation option pragmas
|
compilation option pragmas
|
||||||
--------------------------
|
--------------------------
|
||||||
The listed pragmas here can be used to override the code generation options
|
The listed pragmas here can be used to override the code generation options
|
||||||
for a section of code.
|
for a proc/method/converter.
|
||||||
|
|
||||||
The implementation currently provides the following possible options (various
|
The implementation currently provides the following possible options (various
|
||||||
others may be added later).
|
others may be added later).
|
||||||
|
|
@ -5490,10 +5544,10 @@ spelled*:
|
||||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||||
|
|
||||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
||||||
the same feature under the same name. Also, if you are interfacing with C++
|
the same feature under the same name. Also, if one is interfacing with C++
|
||||||
you can use the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and
|
the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and
|
||||||
interfacing with Objective-C the `ImportObjC pragma
|
interfacing with Objective-C the `ImportObjC pragma
|
||||||
<nimrodc.html#importobjc-pragma>`_.
|
<nimrodc.html#importobjc-pragma>`_ can be used.
|
||||||
|
|
||||||
|
|
||||||
Exportc pragma
|
Exportc pragma
|
||||||
|
|
@ -5781,12 +5835,14 @@ used instead. `spawn`:idx: is used to pass a task to the thread pool:
|
||||||
|
|
||||||
Currently the expression that ``spawn`` takes is however quite restricted:
|
Currently the expression that ``spawn`` takes is however quite restricted:
|
||||||
|
|
||||||
* It must be a call expresion ``f(a, ...)``.
|
* It must be a call expression ``f(a, ...)``.
|
||||||
* ``f`` must be ``gcsafe``.
|
* ``f`` must be ``gcsafe``.
|
||||||
* ``f`` must not have the calling convention ``closure``.
|
* ``f`` must not have the calling convention ``closure``.
|
||||||
* ``f``'s parameters may not be of type ``var`` nor may they contain ``ref``.
|
* ``f``'s parameters may not be of type ``var``.
|
||||||
This means you have to use raw ``ptr``'s for data passing reminding the
|
This means one has to use raw ``ptr``'s for data passing reminding the
|
||||||
programmer to be careful.
|
programmer to be careful.
|
||||||
|
* ``ref`` parameters are deeply copied which is a subtle semantic change and
|
||||||
|
can cause performance problems but ensures memory safety.
|
||||||
* For *safe* data exchange between ``f`` and the caller a global ``TChannel``
|
* For *safe* data exchange between ``f`` and the caller a global ``TChannel``
|
||||||
needs to be used. Other means will be provided soon.
|
needs to be used. Other means will be provided soon.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ customize this style sheet.
|
||||||
Andreas Rumpf
|
Andreas Rumpf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* used to remove borders from tables and images */
|
/* used to remove borders from tables and images */
|
||||||
.borderless, table.borderless td, table.borderless th {
|
.borderless, table.borderless td, table.borderless th {
|
||||||
border: 0 }
|
border: 0 }
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,9 @@ Generated C code directory
|
||||||
--------------------------
|
--------------------------
|
||||||
The generated files that Nimrod produces all go into a subdirectory called
|
The generated files that Nimrod produces all go into a subdirectory called
|
||||||
``nimcache`` in your project directory. This makes it easy to delete all
|
``nimcache`` in your project directory. This makes it easy to delete all
|
||||||
generated files.
|
generated files. Files generated in this directory follow a naming logic which
|
||||||
|
you can read about in the `Nimrod Backend Integration document
|
||||||
|
<backends.html#nimcache-naming-logic>`_.
|
||||||
|
|
||||||
However, the generated C code is not platform independent. C code generated for
|
However, the generated C code is not platform independent. C code generated for
|
||||||
Linux does not compile on Windows, for instance. The comment on top of the
|
Linux does not compile on Windows, for instance. The comment on top of the
|
||||||
|
|
@ -540,6 +542,58 @@ in C/C++).
|
||||||
**Note**: This pragma will not exist for the LLVM backend.
|
**Note**: This pragma will not exist for the LLVM backend.
|
||||||
|
|
||||||
|
|
||||||
|
Source code style
|
||||||
|
=================
|
||||||
|
|
||||||
|
Nimrod allows you to `mix freely case and underscores as identifier separators
|
||||||
|
<manual.html#identifiers-keywords>`_, so variables named ``MyPrecioussInt`` and
|
||||||
|
``my_preciouss_int`` are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var MyPrecioussInt = 3
|
||||||
|
# Following line compiles fine!
|
||||||
|
echo my_preciouss_int
|
||||||
|
|
||||||
|
Since this can lead to many variants of the same source code (you can use
|
||||||
|
`nimgrep <nimgrep.html>`_ instead of your typical ``grep`` to ignore style
|
||||||
|
problems) the compiler provides the command ``pretty`` to help unifying the
|
||||||
|
style of source code. Running ``nimrod pretty ugly_test.nim`` with this
|
||||||
|
example will generate a secondary file named ``ugly_test.pretty.nim`` with the
|
||||||
|
following content:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var MyPrecioussInt = 3
|
||||||
|
# Following line compiles fine!
|
||||||
|
echo MyPrecioussInt
|
||||||
|
|
||||||
|
During execution the ``pretty`` command will also run on Nimrod's standard
|
||||||
|
library, since it doesn't differentiate the standard library as something
|
||||||
|
special, and hence will warn of many *errors* which are out of your hand to
|
||||||
|
fix, creating respective ``.pretty.nim`` files all the way. You can ignore
|
||||||
|
these errors if they don't belong to your source and simply compare your
|
||||||
|
original version to the new pretty one. In fact, running ``pretty`` on our test
|
||||||
|
file will show the following::
|
||||||
|
|
||||||
|
Hint: ugly_test [Processing]
|
||||||
|
ugly_test.nim(1, 4) Error: name should be: myPrecioussInt
|
||||||
|
ugly_test.nim(1, 4) Error: name should be: myPrecioussInt
|
||||||
|
|
||||||
|
At the moment ``pretty`` will homogenize the style of symbols but will leave
|
||||||
|
important changes for you to review. In this case the command is warning that a
|
||||||
|
variable name should not start with a capital letter, which is usually reserved
|
||||||
|
to `object types <tut2.html#objects>`_. To learn about the accepted `camel case
|
||||||
|
style <https://en.wikipedia.org/wiki/Camelcase>`_ read `Coding Guidelines in
|
||||||
|
the Internals of Nimrod Compiler <intern.html#coding-guidelines>`_ or `Coding
|
||||||
|
Guidelines <https://github.com/Araq/Nimrod/wiki/Coding-Guidelines>`_ and `NEP 1
|
||||||
|
: Style Guide for Nimrod Code
|
||||||
|
<https://github.com/Araq/Nimrod/wiki/NEP-1-:-Style-Guide-for-Nimrod-Code>`_
|
||||||
|
from the Nimrod `GitHub wiki<https://github.com/Araq/Nimrod/wiki>`_.
|
||||||
|
|
||||||
|
This command is safe to run because it will never attempt to overwrite your
|
||||||
|
existing sources, but the respective ``.pretty.nim`` files **will** be
|
||||||
|
overwritten without notice.
|
||||||
|
|
||||||
|
|
||||||
DynlibOverride
|
DynlibOverride
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
|
||||||
40
doc/sets_fragment.txt
Normal file
40
doc/sets_fragment.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
The set type models the mathematical notion of a set. The set's
|
||||||
|
basetype can only be an ordinal type. The reason is that sets are implemented
|
||||||
|
as high performance bit vectors.
|
||||||
|
|
||||||
|
Sets can be constructed via the set constructor: ``{}`` is the empty set. The
|
||||||
|
empty set is type compatible with any concrete set type. The constructor
|
||||||
|
can also be used to include elements (and ranges of elements):
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
TCharSet = set[char]
|
||||||
|
var
|
||||||
|
x: TCharSet
|
||||||
|
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
|
||||||
|
# letters from 'a' to 'z' and the digits
|
||||||
|
# from '0' to '9'
|
||||||
|
|
||||||
|
These operations are supported by sets:
|
||||||
|
|
||||||
|
================== ========================================================
|
||||||
|
operation meaning
|
||||||
|
================== ========================================================
|
||||||
|
``A + B`` union of two sets
|
||||||
|
``A * B`` intersection of two sets
|
||||||
|
``A - B`` difference of two sets (A without B's elements)
|
||||||
|
``A == B`` set equality
|
||||||
|
``A <= B`` subset relation (A is subset of B or equal to B)
|
||||||
|
``A < B`` strong subset relation (A is a real subset of B)
|
||||||
|
``e in A`` set membership (A contains element e)
|
||||||
|
``e notin A`` A does not contain element e
|
||||||
|
``contains(A, e)`` A contains element e
|
||||||
|
``A -+- B`` symmetric set difference (= (A - B) + (B - A))
|
||||||
|
``card(A)`` the cardinality of A (number of elements in A)
|
||||||
|
``incl(A, elem)`` same as ``A = A + {elem}``
|
||||||
|
``excl(A, elem)`` same as ``A = A - {elem}``
|
||||||
|
================== ========================================================
|
||||||
|
|
||||||
|
Sets are often used to define a type for the *flags* of a procedure. This is
|
||||||
|
a much cleaner (and type safe) solution than just defining integer
|
||||||
|
constants that should be ``or``'ed together.
|
||||||
|
|
@ -53,13 +53,13 @@ restrictions / changes:
|
||||||
* ``spawn`` within a ``parallel`` section has special semantics.
|
* ``spawn`` within a ``parallel`` section has special semantics.
|
||||||
* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where
|
* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where
|
||||||
``dest`` is part of the pattern ``dest = spawn f(...)`` has to be
|
``dest`` is part of the pattern ``dest = spawn f(...)`` has to be
|
||||||
provable disjoint. This is called the *disjoint check*.
|
provably disjoint. This is called the *disjoint check*.
|
||||||
* Every other complex location ``loc`` that is used in a spawned
|
* Every other complex location ``loc`` that is used in a spawned
|
||||||
proc (``spawn f(loc)``) has to be immutable for the duration of
|
proc (``spawn f(loc)``) has to be immutable for the duration of
|
||||||
the ``parallel`` section. This is called the *immutability check*. Currently
|
the ``parallel`` section. This is called the *immutability check*. Currently
|
||||||
it is not specified what exactly "complex location" means. We need to make
|
it is not specified what exactly "complex location" means. We need to make
|
||||||
this an optimization!
|
this an optimization!
|
||||||
* Every array access has to be provable within bounds. This is called
|
* Every array access has to be provably within bounds. This is called
|
||||||
the *bounds check*.
|
the *bounds check*.
|
||||||
* Slices are optimized so that no copy is performed. This optimization is not
|
* Slices are optimized so that no copy is performed. This optimization is not
|
||||||
yet performed for ordinary slices outside of a ``parallel`` section. Slices
|
yet performed for ordinary slices outside of a ``parallel`` section. Slices
|
||||||
|
|
|
||||||
234
doc/tut1.txt
234
doc/tut1.txt
|
|
@ -18,9 +18,8 @@ Introduction
|
||||||
|
|
||||||
This document is a tutorial for the programming language *Nimrod*.
|
This document is a tutorial for the programming language *Nimrod*.
|
||||||
This tutorial assumes that you are familiar with basic programming concepts
|
This tutorial assumes that you are familiar with basic programming concepts
|
||||||
like variables, types or statements but is kept very basic. The manual
|
like variables, types or statements but is kept very basic. The `manual
|
||||||
contains many more examples of the advanced language features.
|
<manual.html>`_ contains many more examples of the advanced language features.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -40,9 +39,9 @@ Save this code to the file "greetings.nim". Now compile and run it::
|
||||||
|
|
||||||
nimrod compile --run greetings.nim
|
nimrod compile --run greetings.nim
|
||||||
|
|
||||||
With the ``--run`` switch Nimrod executes the file automatically
|
With the ``--run`` `switch <nimrodc.html#command-line-switches>`_ Nimrod
|
||||||
after compilation. You can give your program command line arguments by
|
executes the file automatically after compilation. You can give your program
|
||||||
appending them after the filename::
|
command line arguments by appending them after the filename::
|
||||||
|
|
||||||
nimrod compile --run greetings.nim arg1 arg2
|
nimrod compile --run greetings.nim arg1 arg2
|
||||||
|
|
||||||
|
|
@ -56,7 +55,8 @@ To compile a release version use::
|
||||||
|
|
||||||
By default the Nimrod compiler generates a large amount of runtime checks
|
By default the Nimrod compiler generates a large amount of runtime checks
|
||||||
aiming for your debugging pleasure. With ``-d:release`` these checks are
|
aiming for your debugging pleasure. With ``-d:release`` these checks are
|
||||||
turned off and optimizations are turned on.
|
`turned off and optimizations are turned on
|
||||||
|
<nimrodc.html#compile-time-symbols>`_.
|
||||||
|
|
||||||
Though it should be pretty obvious what the program does, I will explain the
|
Though it should be pretty obvious what the program does, I will explain the
|
||||||
syntax: statements which are not indented are executed when the program
|
syntax: statements which are not indented are executed when the program
|
||||||
|
|
@ -65,9 +65,10 @@ done with spaces only, tabulators are not allowed.
|
||||||
|
|
||||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||||
a new variable named ``name`` of type ``string`` with the value that is
|
a new variable named ``name`` of type ``string`` with the value that is
|
||||||
returned by the ``readLine`` procedure. Since the compiler knows that
|
returned by the `readLine <system.html#readLine,TFile>`_ procedure. Since the
|
||||||
``readLine`` returns a string, you can leave out the type in the declaration
|
compiler knows that `readLine <system.html#readLine,TFile>`_ returns a string,
|
||||||
(this is called `local type inference`:idx:). So this will work too:
|
you can leave out the type in the declaration (this is called `local type
|
||||||
|
inference`:idx:). So this will work too:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
var name = readLine(stdin)
|
var name = readLine(stdin)
|
||||||
|
|
@ -75,10 +76,10 @@ returned by the ``readLine`` procedure. Since the compiler knows that
|
||||||
Note that this is basically the only form of type inference that exists in
|
Note that this is basically the only form of type inference that exists in
|
||||||
Nimrod: it is a good compromise between brevity and readability.
|
Nimrod: it is a good compromise between brevity and readability.
|
||||||
|
|
||||||
The "hello world" program contains several identifiers that are already
|
The "hello world" program contains several identifiers that are already known
|
||||||
known to the compiler: ``echo``, ``readLine``, etc. These built-ins are
|
to the compiler: ``echo``, `readLine <system.html#readLine,TFile>`_, etc.
|
||||||
declared in the system_ module which is implicitly imported by any other
|
These built-ins are declared in the system_ module which is implicitly
|
||||||
module.
|
imported by any other module.
|
||||||
|
|
||||||
|
|
||||||
Lexical elements
|
Lexical elements
|
||||||
|
|
@ -154,11 +155,11 @@ the syntax, watch their indentation:
|
||||||
when false:
|
when false:
|
||||||
brokenCode()
|
brokenCode()
|
||||||
|
|
||||||
Another option is to use the `discard`_ statement together with
|
Another option is to use the `discard statement`_ together with *long string
|
||||||
*long string literals* to create block comments:
|
literals* to create block comments:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
discard """ You can have any nimrod code text commented
|
discard """ You can have any Nimrod code text commented
|
||||||
out inside this with no indentation restrictions.
|
out inside this with no indentation restrictions.
|
||||||
yes("May I ask a pointless question?") """
|
yes("May I ask a pointless question?") """
|
||||||
|
|
||||||
|
|
@ -257,10 +258,10 @@ that can not be re-assigned, ``const`` means "enforce compile time evaluation
|
||||||
and put it into a data section":
|
and put it into a data section":
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
const input = readline(stdin) # Error: constant expression expected
|
const input = readLine(stdin) # Error: constant expression expected
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
let input = readline(stdin) # works
|
let input = readLine(stdin) # works
|
||||||
|
|
||||||
|
|
||||||
Control flow statements
|
Control flow statements
|
||||||
|
|
@ -285,9 +286,10 @@ The if statement is one way to branch the control flow:
|
||||||
else:
|
else:
|
||||||
echo("Hi, ", name, "!")
|
echo("Hi, ", name, "!")
|
||||||
|
|
||||||
There can be zero or more elif parts, and the else part is optional. The
|
There can be zero or more ``elif`` parts, and the ``else`` part is optional.
|
||||||
keyword ``elif`` is short for ``else if``, and is useful to avoid excessive
|
The keyword ``elif`` is short for ``else if``, and is useful to avoid
|
||||||
indentation. (The ``""`` is the empty string. It contains no characters.)
|
excessive indentation. (The ``""`` is the empty string. It contains no
|
||||||
|
characters.)
|
||||||
|
|
||||||
|
|
||||||
Case statement
|
Case statement
|
||||||
|
|
@ -338,7 +340,7 @@ the compiler that for every other value nothing should be done:
|
||||||
of 3, 8: echo("The number is 3 or 8")
|
of 3, 8: echo("The number is 3 or 8")
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
The empty ``discard`` statement is a *do nothing* statement. The compiler knows
|
The empty `discard statement`_ is a *do nothing* statement. The compiler knows
|
||||||
that a case statement with an else part cannot fail and thus the error
|
that a case statement with an else part cannot fail and thus the error
|
||||||
disappears. Note that it is impossible to cover all possible string values:
|
disappears. Note that it is impossible to cover all possible string values:
|
||||||
that is why there is no such check for string cases.
|
that is why there is no such check for string cases.
|
||||||
|
|
@ -370,7 +372,8 @@ For statement
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The ``for`` statement is a construct to loop over any element an *iterator*
|
The ``for`` statement is a construct to loop over any element an *iterator*
|
||||||
provides. The example uses the built-in ``countup`` iterator:
|
provides. The example uses the built-in `countup <system.html#countup>`_
|
||||||
|
iterator:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
echo("Counting to ten: ")
|
echo("Counting to ten: ")
|
||||||
|
|
@ -378,11 +381,11 @@ provides. The example uses the built-in ``countup`` iterator:
|
||||||
echo($i)
|
echo($i)
|
||||||
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
|
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
|
||||||
|
|
||||||
The built-in ``$`` operator turns an integer (``int``) and many other types
|
The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many
|
||||||
into a string. The variable ``i`` is implicitly declared by the ``for`` loop
|
other types into a string. The variable ``i`` is implicitly declared by the
|
||||||
and has the type ``int``, because that is what ``countup`` returns. ``i`` runs
|
``for`` loop and has the type ``int``, because that is what `countup
|
||||||
through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
<system.html#countup>`_ returns. ``i`` runs through the values 1, 2, .., 10.
|
||||||
the same:
|
Each value is ``echo``-ed. This code does the same:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
echo("Counting to 10: ")
|
echo("Counting to 10: ")
|
||||||
|
|
@ -400,8 +403,8 @@ Counting down can be achieved as easily (but is less often needed):
|
||||||
echo($i)
|
echo($i)
|
||||||
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
|
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
|
||||||
|
|
||||||
Since counting up occurs so often in programs, Nimrod also has a ``..`` iterator
|
Since counting up occurs so often in programs, Nimrod also has a `..
|
||||||
that does the same:
|
<system.html#...i,S,T>`_ iterator that does the same:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
for i in 1..10:
|
for i in 1..10:
|
||||||
|
|
@ -553,9 +556,10 @@ an expression is allowed:
|
||||||
Procedures
|
Procedures
|
||||||
==========
|
==========
|
||||||
|
|
||||||
To define new commands like ``echo``, ``readline`` in the examples, the concept
|
To define new commands like `echo <system.html#echo>`_ and `readLine
|
||||||
of a `procedure` is needed. (Some languages call them *methods* or
|
<system.html#readLine,TFile>`_ in the examples, the concept of a `procedure`
|
||||||
*functions*.) In Nimrod new procedures are defined with the ``proc`` keyword:
|
is needed. (Some languages call them *methods* or *functions*.) In Nimrod new
|
||||||
|
procedures are defined with the ``proc`` keyword:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc yes(question: string): bool =
|
proc yes(question: string): bool =
|
||||||
|
|
@ -649,7 +653,7 @@ a tuple as a return value instead of using var parameters.
|
||||||
Discard statement
|
Discard statement
|
||||||
-----------------
|
-----------------
|
||||||
To call a procedure that returns a value just for its side effects and ignoring
|
To call a procedure that returns a value just for its side effects and ignoring
|
||||||
its return value, a discard statement **has** to be used. Nimrod does not
|
its return value, a ``discard`` statement **has** to be used. Nimrod does not
|
||||||
allow to silently throw away a return value:
|
allow to silently throw away a return value:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -665,8 +669,8 @@ been declared with the ``discardable`` pragma:
|
||||||
|
|
||||||
p(3, 4) # now valid
|
p(3, 4) # now valid
|
||||||
|
|
||||||
The discard statement can also be used to create block comments as described
|
The ``discard`` statement can also be used to create block comments as
|
||||||
in the `Comments`_.
|
described in the `Comments`_ section.
|
||||||
|
|
||||||
|
|
||||||
Named arguments
|
Named arguments
|
||||||
|
|
@ -730,12 +734,12 @@ Nimrod provides the ability to overload procedures similar to C++:
|
||||||
echo(toString(13)) # calls the toString(x: int) proc
|
echo(toString(13)) # calls the toString(x: int) proc
|
||||||
echo(toString(true)) # calls the toString(x: bool) proc
|
echo(toString(true)) # calls the toString(x: bool) proc
|
||||||
|
|
||||||
(Note that ``toString`` is usually the ``$`` operator in Nimrod.)
|
(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
|
||||||
The compiler chooses the most appropriate proc for the ``toString`` calls. How
|
Nimrod.) The compiler chooses the most appropriate proc for the ``toString``
|
||||||
this overloading resolution algorithm works exactly is not discussed here
|
calls. How this overloading resolution algorithm works exactly is not
|
||||||
(it will be specified in the manual soon).
|
discussed here (it will be specified in the manual soon). However, it does
|
||||||
However, it does not lead to nasty surprises and is based on a quite simple
|
not lead to nasty surprises and is based on a quite simple unification
|
||||||
unification algorithm. Ambiguous calls are reported as errors.
|
algorithm. Ambiguous calls are reported as errors.
|
||||||
|
|
||||||
|
|
||||||
Operators
|
Operators
|
||||||
|
|
@ -758,7 +762,7 @@ User defined operators are allowed. Nothing stops you from defining your own
|
||||||
The operator's precedence is determined by its first character. The details
|
The operator's precedence is determined by its first character. The details
|
||||||
can be found in the manual.
|
can be found in the manual.
|
||||||
|
|
||||||
To define a new operator enclose the operator in "``":
|
To define a new operator enclose the operator in backticks "``":
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc `$` (x: myDataType): string = ...
|
proc `$` (x: myDataType): string = ...
|
||||||
|
|
@ -811,7 +815,8 @@ Let's return to the boring counting example:
|
||||||
for i in countup(1, 10):
|
for i in countup(1, 10):
|
||||||
echo($i)
|
echo($i)
|
||||||
|
|
||||||
Can a ``countup`` proc be written that supports this loop? Lets try:
|
Can a `countup <system.html#countup>`_ proc be written that supports this
|
||||||
|
loop? Lets try:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc countup(a, b: int): int =
|
proc countup(a, b: int): int =
|
||||||
|
|
@ -976,24 +981,25 @@ type:
|
||||||
The common operators ``+ - * / < <= == != > >=`` are defined for
|
The common operators ``+ - * / < <= == != > >=`` are defined for
|
||||||
floats and follow the IEEE standard.
|
floats and follow the IEEE standard.
|
||||||
|
|
||||||
Automatic type conversion in expressions with different kinds
|
Automatic type conversion in expressions with different kinds of floating
|
||||||
of floating point types is performed: the smaller type is
|
point types is performed: the smaller type is converted to the larger. Integer
|
||||||
converted to the larger. Integer types are **not** converted to floating point
|
types are **not** converted to floating point types automatically and vice
|
||||||
types automatically and vice versa. The ``toInt`` and ``toFloat`` procs can be
|
versa. The `toInt <system.html#toInt>`_ and `toFloat <system.html#toFloat>`_
|
||||||
used for these conversions.
|
procs can be used for these conversions.
|
||||||
|
|
||||||
|
|
||||||
Internal type representation
|
Internal type representation
|
||||||
============================
|
============================
|
||||||
|
|
||||||
As mentioned earlier, the built-in ``$`` (stringify) operator turns any basic
|
As mentioned earlier, the built-in `$ <system.html#$>`_ (stringify) operator
|
||||||
type into a string, which you can then print to the screen with the ``echo``
|
turns any basic type into a string, which you can then print to the screen
|
||||||
proc. However, advanced types, or types you may define yourself won't work with
|
with the ``echo`` proc. However, advanced types, or types you may define
|
||||||
the ``$`` operator until you define one for them. Sometimes you just want to
|
yourself won't work with the ``$`` operator until you define one for them.
|
||||||
debug the current value of a complex type without having to write its ``$``
|
Sometimes you just want to debug the current value of a complex type without
|
||||||
operator. You can use then the ``repr`` proc which works with any type and
|
having to write its ``$`` operator. You can use then the `repr
|
||||||
even complex data graphs with cycles. The following example shows that even for
|
<system.html#repr>`_ proc which works with any type and even complex data
|
||||||
basic types there is a difference between the ``$`` and ``repr`` outputs:
|
graphs with cycles. The following example shows that even for basic types
|
||||||
|
there is a difference between the ``$`` and ``repr`` outputs:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
var
|
var
|
||||||
|
|
@ -1087,9 +1093,10 @@ Operation Comment
|
||||||
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
||||||
----------------- --------------------------------------------------------
|
----------------- --------------------------------------------------------
|
||||||
|
|
||||||
The ``inc dec succ pred`` operations can fail by raising an `EOutOfRange` or
|
The `inc <system.html#inc>`_, `dec <system.html#dec>`_, `succ
|
||||||
`EOverflow` exception. (If the code has been compiled with the proper runtime
|
<system.html#succ>`_ and `pred <system.html#pred>`_ operations can fail by
|
||||||
checks turned on.)
|
raising an `EOutOfRange` or `EOverflow` exception. (If the code has been
|
||||||
|
compiled with the proper runtime checks turned on.)
|
||||||
|
|
||||||
|
|
||||||
Subranges
|
Subranges
|
||||||
|
|
@ -1107,57 +1114,18 @@ to 5. Assigning any other value to a variable of type ``TSubrange`` is a
|
||||||
compile-time or runtime error. Assignments from the base type to one of its
|
compile-time or runtime error. Assignments from the base type to one of its
|
||||||
subrange types (and vice versa) are allowed.
|
subrange types (and vice versa) are allowed.
|
||||||
|
|
||||||
The ``system`` module defines the important ``natural`` type as
|
The ``system`` module defines the important `Natural <system.html#Natural>`_
|
||||||
``range[0..high(int)]`` (``high`` returns the maximal value). Other programming
|
type as ``range[0..high(int)]`` (`high <system.html#high>`_ returns the
|
||||||
languages mandate the usage of unsigned integers for natural numbers. This is
|
maximal value). Other programming languages mandate the usage of unsigned
|
||||||
often **wrong**: you don't want unsigned arithmetic (which wraps around) just
|
integers for natural numbers. This is often **wrong**: you don't want unsigned
|
||||||
because the numbers cannot be negative. Nimrod's ``natural`` type helps to
|
arithmetic (which wraps around) just because the numbers cannot be negative.
|
||||||
avoid this common programming error.
|
Nimrod's ``Natural`` type helps to avoid this common programming error.
|
||||||
|
|
||||||
|
|
||||||
Sets
|
Sets
|
||||||
----
|
----
|
||||||
The set type models the mathematical notion of a set. The set's
|
|
||||||
basetype can only be an ordinal type. The reason is that sets are implemented
|
|
||||||
as high performance bit vectors.
|
|
||||||
|
|
||||||
Sets can be constructed via the set constructor: ``{}`` is the empty set. The
|
|
||||||
empty set is type compatible with any concrete set type. The constructor
|
|
||||||
can also be used to include elements (and ranges of elements):
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
|
||||||
type
|
|
||||||
TCharSet = set[char]
|
|
||||||
var
|
|
||||||
x: TCharSet
|
|
||||||
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
|
|
||||||
# letters from 'a' to 'z' and the digits
|
|
||||||
# from '0' to '9'
|
|
||||||
|
|
||||||
These operations are supported by sets:
|
|
||||||
|
|
||||||
================== ========================================================
|
|
||||||
operation meaning
|
|
||||||
================== ========================================================
|
|
||||||
``A + B`` union of two sets
|
|
||||||
``A * B`` intersection of two sets
|
|
||||||
``A - B`` difference of two sets (A without B's elements)
|
|
||||||
``A == B`` set equality
|
|
||||||
``A <= B`` subset relation (A is subset of B or equal to B)
|
|
||||||
``A < B`` strong subset relation (A is a real subset of B)
|
|
||||||
``e in A`` set membership (A contains element e)
|
|
||||||
``e notin A`` A does not contain element e
|
|
||||||
``contains(A, e)`` A contains element e
|
|
||||||
``A -+- B`` symmetric set difference (= (A - B) + (B - A))
|
|
||||||
``card(A)`` the cardinality of A (number of elements in A)
|
|
||||||
``incl(A, elem)`` same as ``A = A + {elem}``
|
|
||||||
``excl(A, elem)`` same as ``A = A - {elem}``
|
|
||||||
================== ========================================================
|
|
||||||
|
|
||||||
Sets are often used to define a type for the *flags* of a procedure. This is
|
|
||||||
a much cleaner (and type safe) solution than just defining integer
|
|
||||||
constants that should be ``or``'ed together.
|
|
||||||
|
|
||||||
|
.. include:: sets_fragment.txt
|
||||||
|
|
||||||
Arrays
|
Arrays
|
||||||
------
|
------
|
||||||
|
|
@ -1184,8 +1152,9 @@ checks can be disabled via pragmas or invoking the compiler with the
|
||||||
Arrays are value types, like any other Nimrod type. The assignment operator
|
Arrays are value types, like any other Nimrod type. The assignment operator
|
||||||
copies the whole array contents.
|
copies the whole array contents.
|
||||||
|
|
||||||
The built-in ``len`` proc returns the array's length. ``low(a)`` returns the
|
The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's
|
||||||
lowest valid index for the array `a` and ``high(a)`` the highest valid index.
|
length. `low(a) <system.html#low>`_ returns the lowest valid index for the
|
||||||
|
array `a` and `high(a) <system.html#high>`_ the highest valid index.
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
|
|
@ -1257,13 +1226,14 @@ Sequences are similar to arrays but of dynamic length which may change
|
||||||
during runtime (like strings). Since sequences are resizable they are always
|
during runtime (like strings). Since sequences are resizable they are always
|
||||||
allocated on the heap and garbage collected.
|
allocated on the heap and garbage collected.
|
||||||
|
|
||||||
Sequences are always indexed with an ``int`` starting at position 0.
|
Sequences are always indexed with an ``int`` starting at position 0. The `len
|
||||||
The ``len``, ``low`` and ``high`` operations are available for sequences too.
|
<system.html#len,seq[T]>`_, `low <system.html#low>`_ and `high
|
||||||
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
<system.html#high>`_ operations are available for sequences too. The notation
|
||||||
|
``x[i]`` can be used to access the i-th element of ``x``.
|
||||||
|
|
||||||
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
||||||
with the array to sequence operator ``@``. Another way to allocate space for
|
with the array to sequence operator ``@``. Another way to allocate space for
|
||||||
a sequence is to call the built-in ``newSeq`` procedure.
|
a sequence is to call the built-in `newSeq <system.html#newSeq>`_ procedure.
|
||||||
|
|
||||||
A sequence may be passed to an openarray parameter.
|
A sequence may be passed to an openarray parameter.
|
||||||
|
|
||||||
|
|
@ -1284,10 +1254,11 @@ object on the heap, so there is a trade-off to be made here.
|
||||||
The ``for`` statement can be used with one or two variables when used with a
|
The ``for`` statement can be used with one or two variables when used with a
|
||||||
sequence. When you use the one variable form, the variable will hold the value
|
sequence. When you use the one variable form, the variable will hold the value
|
||||||
provided by the sequence. The ``for`` statement is looping over the results
|
provided by the sequence. The ``for`` statement is looping over the results
|
||||||
from the ``items()`` iterator from the `system <system.html>`_ module. But if
|
from the `items() <system.html#items.i,seq[T]>`_ iterator from the `system
|
||||||
you use the two variable form, the first variable will hold the index position
|
<system.html>`_ module. But if you use the two variable form, the first
|
||||||
and the second variable will hold the value. Here the ``for`` statement is
|
variable will hold the index position and the second variable will hold the
|
||||||
looping over the results from the ``pairs()`` iterator from the `system
|
value. Here the ``for`` statement is looping over the results from the
|
||||||
|
`pairs() <system.html#pairs.i,seq[T]>`_ iterator from the `system
|
||||||
<system.html>`_ module. Examples:
|
<system.html>`_ module. Examples:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -1308,12 +1279,13 @@ Open arrays
|
||||||
-----------
|
-----------
|
||||||
**Note**: Openarrays can only be used for parameters.
|
**Note**: Openarrays can only be used for parameters.
|
||||||
|
|
||||||
Often fixed size arrays turn out to be too inflexible; procedures should
|
Often fixed size arrays turn out to be too inflexible; procedures should be
|
||||||
be able to deal with arrays of different sizes. The `openarray`:idx: type
|
able to deal with arrays of different sizes. The `openarray`:idx: type allows
|
||||||
allows this. Openarrays are always indexed with an ``int`` starting at
|
this. Openarrays are always indexed with an ``int`` starting at position 0.
|
||||||
position 0. The ``len``, ``low`` and ``high`` operations are available
|
The `len <system.html#len,TOpenArray>`_, `low <system.html#low>`_ and `high
|
||||||
for open arrays too. Any array with a compatible base type can be passed to
|
<system.html#high>`_ operations are available for open arrays too. Any array
|
||||||
an openarray parameter, the index type does not matter.
|
with a compatible base type can be passed to an openarray parameter, the index
|
||||||
|
type does not matter.
|
||||||
|
|
||||||
The openarray type cannot be nested: multidimensional openarrays are not
|
The openarray type cannot be nested: multidimensional openarrays are not
|
||||||
supported because this is seldom needed and cannot be done efficiently.
|
supported because this is seldom needed and cannot be done efficiently.
|
||||||
|
|
@ -1351,8 +1323,9 @@ type conversions in this context:
|
||||||
# is transformed by the compiler to:
|
# is transformed by the compiler to:
|
||||||
myWriteln(stdout, [$123, $"def", $4.0])
|
myWriteln(stdout, [$123, $"def", $4.0])
|
||||||
|
|
||||||
In this example ``$`` is applied to any argument that is passed to the
|
In this example `$ <system.html#$>`_ is applied to any argument that is passed
|
||||||
parameter ``a``. Note that ``$`` applied to strings is a nop.
|
to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
|
||||||
|
nop.
|
||||||
|
|
||||||
|
|
||||||
Slices
|
Slices
|
||||||
|
|
@ -1431,11 +1404,12 @@ having the same field types.
|
||||||
|
|
||||||
Tuples can be *unpacked* during variable assignment (and only then!). This can
|
Tuples can be *unpacked* during variable assignment (and only then!). This can
|
||||||
be handy to assign directly the fields of the tuples to individually named
|
be handy to assign directly the fields of the tuples to individually named
|
||||||
variables. An example of this is the ``splitFile`` proc from the `os module
|
variables. An example of this is the `splitFile <os.html#splitFile>`_ proc
|
||||||
<os.html>`_ which returns the directory, name and extension of a path at the
|
from the `os module <os.html>`_ which returns the directory, name and
|
||||||
same time. For tuple unpacking to work you have to use parenthesis around the
|
extension of a path at the same time. For tuple unpacking to work you have to
|
||||||
values you want to assign the unpacking to, otherwise you will be assigning the
|
use parenthesis around the values you want to assign the unpacking to,
|
||||||
same value to all the individual variables! Example:
|
otherwise you will be assigning the same value to all the individual
|
||||||
|
variables! Example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
|
|
||||||
59
doc/tut2.txt
59
doc/tut2.txt
|
|
@ -23,11 +23,13 @@ features.**
|
||||||
|
|
||||||
Pragmas
|
Pragmas
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Pragmas are Nimrod's method to give the compiler additional information/
|
Pragmas are Nimrod's method to give the compiler additional information/
|
||||||
commands without introducing a massive number of new keywords. Pragmas are
|
commands without introducing a massive number of new keywords. Pragmas are
|
||||||
enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial
|
enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial
|
||||||
does not cover pragmas. See the `manual <manual.html>`_
|
does not cover pragmas. See the `manual <manual.html#pragmas>`_ or `user guide
|
||||||
or `user guide <nimrodc.html>`_ for a description of the available pragmas.
|
<nimrodc.html#additional-features>`_ for a description of the available
|
||||||
|
pragmas.
|
||||||
|
|
||||||
|
|
||||||
Object Oriented Programming
|
Object Oriented Programming
|
||||||
|
|
@ -421,9 +423,10 @@ the rest of the procedure - that is not within a ``finally`` clause -
|
||||||
is not executed (if an exception occurs).
|
is not executed (if an exception occurs).
|
||||||
|
|
||||||
If you need to *access* the actual exception object or message inside an
|
If you need to *access* the actual exception object or message inside an
|
||||||
``except`` branch you can use the getCurrentException() and
|
``except`` branch you can use the `getCurrentException()
|
||||||
getCurrentExceptionMsg() procs from the `system <system.html>`_ module.
|
<system.html#getCurrentException>`_ and `getCurrentExceptionMsg()
|
||||||
Example:
|
<system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_
|
||||||
|
module. Example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
try:
|
try:
|
||||||
|
|
@ -435,48 +438,6 @@ Example:
|
||||||
echo "Got exception ", repr(e), " with message ", msg
|
echo "Got exception ", repr(e), " with message ", msg
|
||||||
|
|
||||||
|
|
||||||
Exception hierarchy
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
If you want to create your own exceptions you can inherit from E_Base, but you
|
|
||||||
can also inherit from one of the existing exceptions if they fit your purpose.
|
|
||||||
The exception tree is::
|
|
||||||
|
|
||||||
* E_Base
|
|
||||||
* EAsynch
|
|
||||||
* EControlC
|
|
||||||
* ESynch
|
|
||||||
* ESystem
|
|
||||||
* EIO
|
|
||||||
* EOS
|
|
||||||
* EInvalidLibrary
|
|
||||||
* EResourceExhausted
|
|
||||||
* EOutOfMemory
|
|
||||||
* EStackOverflow
|
|
||||||
* EArithmetic
|
|
||||||
* EDivByZero
|
|
||||||
* EOverflow
|
|
||||||
* EAccessViolation
|
|
||||||
* EAssertionFailed
|
|
||||||
* EInvalidValue
|
|
||||||
* EInvalidKey
|
|
||||||
* EInvalidIndex
|
|
||||||
* EInvalidField
|
|
||||||
* EOutOfRange
|
|
||||||
* ENoExceptionToReraise
|
|
||||||
* EInvalidObjectAssignment
|
|
||||||
* EInvalidObjectConversion
|
|
||||||
* EFloatingPoint
|
|
||||||
* EFloatInvalidOp
|
|
||||||
* EFloatDivByZero
|
|
||||||
* EFloatOverflow
|
|
||||||
* EFloatUnderflow
|
|
||||||
* EFloatInexact
|
|
||||||
* EDeadThread
|
|
||||||
|
|
||||||
See the `system <system.html>`_ module for a description of each exception.
|
|
||||||
|
|
||||||
|
|
||||||
Annotating procs with raised exceptions
|
Annotating procs with raised exceptions
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
|
@ -663,8 +624,8 @@ statement:
|
||||||
declareInNewScope(b, int)
|
declareInNewScope(b, int)
|
||||||
b = 42 # does not work, `b` is unknown
|
b = 42 # does not work, `b` is unknown
|
||||||
|
|
||||||
(The manual explains why the ``immediate`` pragma is needed for these
|
(The `manual explains <manual.html#ordinary-vs-immediate-templates>`_ why the
|
||||||
templates.)
|
``immediate`` pragma is needed for these templates.)
|
||||||
|
|
||||||
If there is a ``stmt`` parameter it should be the last in the template
|
If there is a ``stmt`` parameter it should be the last in the template
|
||||||
declaration. The reason is that statements can be passed to a template
|
declaration. The reason is that statements can be passed to a template
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import zmq
|
|
||||||
|
|
||||||
var connection = zmq.open("tcp://localhost:5555", server=false)
|
|
||||||
|
|
||||||
echo("Connecting...")
|
|
||||||
|
|
||||||
for i in 0..10:
|
|
||||||
echo("Sending hello...", i)
|
|
||||||
send(connection, "Hello")
|
|
||||||
|
|
||||||
var reply = receive(connection)
|
|
||||||
echo("Received ...", reply)
|
|
||||||
|
|
||||||
close(connection)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import zmq
|
|
||||||
|
|
||||||
var connection = zmq.open("tcp://*:5555", server=true)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
var request = receive(connection)
|
|
||||||
echo("Received: ", request)
|
|
||||||
send(connection, "World")
|
|
||||||
|
|
||||||
close(connection)
|
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424A15BC87B6005EFF20 /* AppDelegate.m */; };
|
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424A15BC87B6005EFF20 /* AppDelegate.m */; };
|
||||||
D531424E15BC87B6005EFF20 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424B15BC87B6005EFF20 /* main.m */; };
|
D531424E15BC87B6005EFF20 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424B15BC87B6005EFF20 /* main.m */; };
|
||||||
D531427215BC94B1005EFF20 /* backend.m in Sources */ = {isa = PBXBuildFile; fileRef = D531426F15BC94B1005EFF20 /* backend.m */; };
|
D531427215BC94B1005EFF20 /* backend.m in Sources */ = {isa = PBXBuildFile; fileRef = D531426F15BC94B1005EFF20 /* backend.m */; };
|
||||||
D531427415BC94B1005EFF20 /* system.m in Sources */ = {isa = PBXBuildFile; fileRef = D531427115BC94B1005EFF20 /* system.m */; };
|
D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */ = {isa = PBXBuildFile; fileRef = D531427115BC94B1005EFF20 /* stdlib_system.m */; };
|
||||||
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B6F94615FA8D4C0084A85B /* NRViewController.m */; };
|
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B6F94615FA8D4C0084A85B /* NRViewController.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
D531426715BC91EF005EFF20 /* tags.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = tags.sh; path = scripts/tags.sh; sourceTree = "<group>"; };
|
D531426715BC91EF005EFF20 /* tags.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = tags.sh; path = scripts/tags.sh; sourceTree = "<group>"; };
|
||||||
D531426815BC91EF005EFF20 /* xcode_prebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = xcode_prebuild.sh; path = scripts/xcode_prebuild.sh; sourceTree = "<group>"; };
|
D531426815BC91EF005EFF20 /* xcode_prebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = xcode_prebuild.sh; path = scripts/xcode_prebuild.sh; sourceTree = "<group>"; };
|
||||||
D531426F15BC94B1005EFF20 /* backend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = backend.m; path = build/nimcache/backend.m; sourceTree = "<group>"; };
|
D531426F15BC94B1005EFF20 /* backend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = backend.m; path = build/nimcache/backend.m; sourceTree = "<group>"; };
|
||||||
D531427115BC94B1005EFF20 /* system.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = system.m; path = build/nimcache/system.m; sourceTree = "<group>"; };
|
D531427115BC94B1005EFF20 /* stdlib_system.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = stdlib_system.m; path = build/nimcache/stdlib_system.m; sourceTree = "<group>"; };
|
||||||
D592E19015C7120F005258EA /* backend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = backend.h; path = build/nimcache/backend.h; sourceTree = "<group>"; };
|
D592E19015C7120F005258EA /* backend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = backend.h; path = build/nimcache/backend.h; sourceTree = "<group>"; };
|
||||||
D592E19115C71415005258EA /* nimbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nimbase.h; path = build/nimcache/nimbase.h; sourceTree = "<group>"; };
|
D592E19115C71415005258EA /* nimbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nimbase.h; path = build/nimcache/nimbase.h; sourceTree = "<group>"; };
|
||||||
D5B6F94515FA8D4C0084A85B /* NRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NRViewController.h; path = src/NRViewController.h; sourceTree = "<group>"; };
|
D5B6F94515FA8D4C0084A85B /* NRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NRViewController.h; path = src/NRViewController.h; sourceTree = "<group>"; };
|
||||||
|
|
@ -135,7 +135,7 @@
|
||||||
D592E19015C7120F005258EA /* backend.h */,
|
D592E19015C7120F005258EA /* backend.h */,
|
||||||
D531426F15BC94B1005EFF20 /* backend.m */,
|
D531426F15BC94B1005EFF20 /* backend.m */,
|
||||||
D592E19115C71415005258EA /* nimbase.h */,
|
D592E19115C71415005258EA /* nimbase.h */,
|
||||||
D531427115BC94B1005EFF20 /* system.m */,
|
D531427115BC94B1005EFF20 /* stdlib_system.m */,
|
||||||
);
|
);
|
||||||
name = nimrod;
|
name = nimrod;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -229,7 +229,7 @@
|
||||||
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */,
|
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */,
|
||||||
D531424E15BC87B6005EFF20 /* main.m in Sources */,
|
D531424E15BC87B6005EFF20 /* main.m in Sources */,
|
||||||
D531427215BC94B1005EFF20 /* backend.m in Sources */,
|
D531427215BC94B1005EFF20 /* backend.m in Sources */,
|
||||||
D531427415BC94B1005EFF20 /* system.m in Sources */,
|
D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */,
|
||||||
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */,
|
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -259,11 +259,7 @@
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 3.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-weak_library",
|
|
||||||
/usr/lib/libSystem.B.dylib,
|
|
||||||
);
|
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
|
|
@ -284,12 +280,8 @@
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 3.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||||
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-weak_library",
|
|
||||||
/usr/lib/libSystem.B.dylib,
|
|
||||||
);
|
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ DEST_NIMBASE=build/nimcache/nimbase.h
|
||||||
if [ -d src ]
|
if [ -d src ]
|
||||||
then
|
then
|
||||||
$PATH_TO_NIMROD objc --noMain --app:lib \
|
$PATH_TO_NIMROD objc --noMain --app:lib \
|
||||||
--nimcache:build/nimcache --compileOnly \
|
--nimcache:./build/nimcache --compileOnly \
|
||||||
--header --cpu:i386 ../nimrod_backend/backend.nim
|
--header --cpu:i386 ../nimrod_backend/backend.nim
|
||||||
if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
|
if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
|
||||||
then
|
then
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,6 @@ Currently, the following C compilers are supported under Windows:
|
||||||
| http://www.mingw.org/download.shtml
|
| http://www.mingw.org/download.shtml
|
||||||
- | LLVM with Clang or GNU C/C++ frontend
|
- | LLVM with Clang or GNU C/C++ frontend
|
||||||
| http://llvm.org/releases/download.html
|
| http://llvm.org/releases/download.html
|
||||||
- | Digital Mars C++
|
|
||||||
| http://www.digitalmars.com/download/freecompiler.html
|
|
||||||
|
|
||||||
However, most testing is done with GCC.
|
However, most testing is done with GCC.
|
||||||
|
|
||||||
|
|
|
||||||
36
koch.nim
36
koch.nim
|
|
@ -43,7 +43,7 @@ Possible Commands:
|
||||||
web generates the website
|
web generates the website
|
||||||
csource [options] builds the C sources for installation
|
csource [options] builds the C sources for installation
|
||||||
zip builds the installation ZIP package
|
zip builds the installation ZIP package
|
||||||
inno [options] builds the Inno Setup installer (for Windows)
|
nsis [options] builds the NSIS Setup installer (for Windows)
|
||||||
tests [options] run the testsuite
|
tests [options] run the testsuite
|
||||||
update updates nimrod to the latest version from github
|
update updates nimrod to the latest version from github
|
||||||
(compile koch with -d:withUpdate to enable)
|
(compile koch with -d:withUpdate to enable)
|
||||||
|
|
@ -77,6 +77,14 @@ proc tryExec(cmd: string): bool =
|
||||||
echo(cmd)
|
echo(cmd)
|
||||||
result = execShellCmd(cmd) == 0
|
result = execShellCmd(cmd) == 0
|
||||||
|
|
||||||
|
proc safeRemove(filename: string) =
|
||||||
|
if existsFile(filename): removeFile(filename)
|
||||||
|
|
||||||
|
proc copyExe(source, dest: string) =
|
||||||
|
safeRemove(dest)
|
||||||
|
copyFile(dest=dest, source=source)
|
||||||
|
inclFilePermissions(dest, {fpUserExec})
|
||||||
|
|
||||||
const
|
const
|
||||||
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
|
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
|
||||||
|
|
||||||
|
|
@ -85,20 +93,24 @@ proc csource(args: string) =
|
||||||
[args, NimrodVersion, compileNimInst, findNim()])
|
[args, NimrodVersion, compileNimInst, findNim()])
|
||||||
|
|
||||||
proc zip(args: string) =
|
proc zip(args: string) =
|
||||||
exec("$3 cc -r $2 --var:version=$1 zip compiler/nimrod.ini" %
|
exec("$3 cc -r $2 --var:version=$1 --var:mingw=mingw32 scripts compiler/nimrod.ini" %
|
||||||
[NimrodVersion, compileNimInst, findNim()])
|
[NimrodVersion, compileNimInst, findNim()])
|
||||||
|
exec("$# --var:version=$# --var:mingw=mingw32 zip compiler/nimrod.ini" %
|
||||||
|
["tools/niminst/niminst".exe, NimrodVersion])
|
||||||
|
|
||||||
proc buildTool(toolname, args: string) =
|
proc buildTool(toolname, args: string) =
|
||||||
exec("$# cc $# $#" % [findNim(), args, toolname])
|
exec("$# cc $# $#" % [findNim(), args, toolname])
|
||||||
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
|
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
|
||||||
|
|
||||||
proc inno(args: string) =
|
proc nsis(args: string) =
|
||||||
# make sure we have generated the c2nim and niminst executables:
|
# make sure we have generated the niminst executables:
|
||||||
buildTool("tools/niminst/niminst", args)
|
buildTool("tools/niminst/niminst", args)
|
||||||
buildTool("tools/nimgrep", args)
|
buildTool("tools/nimgrep", args)
|
||||||
buildTool("compiler/c2nim/c2nim", args)
|
# produce 'nimrod_debug.exe':
|
||||||
exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nimrod" %
|
exec "nimrod c compiler" / "nimrod.nim"
|
||||||
NimrodVersion)
|
copyExe("compiler/nimrod".exe, "bin/nimrod_debug".exe)
|
||||||
|
exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw32" &
|
||||||
|
" nsis compiler/nimrod") % NimrodVersion)
|
||||||
|
|
||||||
proc install(args: string) =
|
proc install(args: string) =
|
||||||
exec("$# cc -r $# --var:version=$# scripts compiler/nimrod.ini" %
|
exec("$# cc -r $# --var:version=$# scripts compiler/nimrod.ini" %
|
||||||
|
|
@ -136,17 +148,9 @@ proc findStartNimrod: string =
|
||||||
echo("Found no nimrod compiler and every attempt to build one failed!")
|
echo("Found no nimrod compiler and every attempt to build one failed!")
|
||||||
quit("FAILURE")
|
quit("FAILURE")
|
||||||
|
|
||||||
proc safeRemove(filename: string) =
|
|
||||||
if existsFile(filename): removeFile(filename)
|
|
||||||
|
|
||||||
proc thVersion(i: int): string =
|
proc thVersion(i: int): string =
|
||||||
result = ("compiler" / "nimrod" & $i).exe
|
result = ("compiler" / "nimrod" & $i).exe
|
||||||
|
|
||||||
proc copyExe(source, dest: string) =
|
|
||||||
safeRemove(dest)
|
|
||||||
copyFile(dest=dest, source=source)
|
|
||||||
inclFilePermissions(dest, {fpUserExec})
|
|
||||||
|
|
||||||
proc boot(args: string) =
|
proc boot(args: string) =
|
||||||
var output = "compiler" / "nimrod".exe
|
var output = "compiler" / "nimrod".exe
|
||||||
var finalDest = "bin" / "nimrod".exe
|
var finalDest = "bin" / "nimrod".exe
|
||||||
|
|
@ -303,7 +307,7 @@ of cmdArgument:
|
||||||
of "web": web(op.cmdLineRest)
|
of "web": web(op.cmdLineRest)
|
||||||
of "csource", "csources": csource(op.cmdLineRest)
|
of "csource", "csources": csource(op.cmdLineRest)
|
||||||
of "zip": zip(op.cmdLineRest)
|
of "zip": zip(op.cmdLineRest)
|
||||||
of "inno": inno(op.cmdLineRest)
|
of "nsis": nsis(op.cmdLineRest)
|
||||||
of "install": install(op.cmdLineRest)
|
of "install": install(op.cmdLineRest)
|
||||||
of "test", "tests": tests(op.cmdLineRest)
|
of "test", "tests": tests(op.cmdLineRest)
|
||||||
of "update":
|
of "update":
|
||||||
|
|
|
||||||
|
|
@ -627,7 +627,7 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
|
||||||
case node.kind
|
case node.kind
|
||||||
of nnkIdent:
|
of nnkIdent:
|
||||||
result = $node.ident
|
result = $node.ident
|
||||||
of nnkStrLit:
|
of nnkStrLit..nnkTripleStrLit:
|
||||||
result = node.strVal
|
result = node.strVal
|
||||||
else:
|
else:
|
||||||
badNodeKind node.kind, "$"
|
badNodeKind node.kind, "$"
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ proc newAny(value: pointer, rawType: PNimType): TAny =
|
||||||
result.value = value
|
result.value = value
|
||||||
result.rawType = rawType
|
result.rawType = rawType
|
||||||
|
|
||||||
when defined(system.TVarSlot):
|
when declared(system.TVarSlot):
|
||||||
proc toAny*(x: TVarSlot): TAny {.inline.} =
|
proc toAny*(x: TVarSlot): TAny {.inline.} =
|
||||||
## constructs a ``TAny`` object from a variable slot ``x``.
|
## constructs a ``TAny`` object from a variable slot ``x``.
|
||||||
## This captures `x`'s address, so `x` can be modified with its
|
## This captures `x`'s address, so `x` can be modified with its
|
||||||
|
|
@ -420,6 +420,59 @@ proc setBiggestInt*(x: TAny, y: biggestInt) =
|
||||||
of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
|
of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
|
||||||
else: assert false
|
else: assert false
|
||||||
|
|
||||||
|
proc getUInt*(x: TAny): uint =
|
||||||
|
## retrieve the uint value out of `x`, `x` needs to represent an uint.
|
||||||
|
assert skipRange(x.rawtype).kind == tyUInt
|
||||||
|
result = cast[ptr uint](x.value)[]
|
||||||
|
|
||||||
|
proc getUInt8*(x: TAny): uint8 =
|
||||||
|
## retrieve the uint8 value out of `x`, `x` needs to represent an
|
||||||
|
## uint8.
|
||||||
|
assert skipRange(x.rawtype).kind == tyUInt8
|
||||||
|
result = cast[ptr uint8](x.value)[]
|
||||||
|
|
||||||
|
proc getUInt16*(x: TAny): uint16 =
|
||||||
|
## retrieve the uint16 value out of `x`, `x` needs to represent an
|
||||||
|
## uint16.
|
||||||
|
assert skipRange(x.rawtype).kind == tyUInt16
|
||||||
|
result = cast[ptr uint16](x.value)[]
|
||||||
|
|
||||||
|
proc getUInt32*(x: TAny): uint32 =
|
||||||
|
## retrieve the uint32 value out of `x`, `x` needs to represent an
|
||||||
|
## uint32.
|
||||||
|
assert skipRange(x.rawtype).kind == tyUInt32
|
||||||
|
result = cast[ptr uint32](x.value)[]
|
||||||
|
|
||||||
|
proc getUInt64*(x: TAny): uint64 =
|
||||||
|
## retrieve the uint64 value out of `x`, `x` needs to represent an
|
||||||
|
## uint64.
|
||||||
|
assert skipRange(x.rawtype).kind == tyUInt64
|
||||||
|
result = cast[ptr uint64](x.value)[]
|
||||||
|
|
||||||
|
proc getBiggestUint*(x: TAny): uint64 =
|
||||||
|
## retrieve the unsigned integer value out of `x`. `x` needs to
|
||||||
|
## represent an unsigned integer.
|
||||||
|
var t = skipRange(x.rawtype)
|
||||||
|
case t.kind
|
||||||
|
of tyUInt: result = uint64(cast[ptr uint](x.value)[])
|
||||||
|
of tyUInt8: result = uint64(cast[ptr uint8](x.value)[])
|
||||||
|
of tyUInt16: result = uint64(cast[ptr uint16](x.value)[])
|
||||||
|
of tyUInt32: result = uint64(cast[ptr uint32](x.value)[])
|
||||||
|
of tyUInt64: result = uint64(cast[ptr uint64](x.value)[])
|
||||||
|
else: assert false
|
||||||
|
|
||||||
|
proc setBiggestUint*(x: TAny; y: uint64) =
|
||||||
|
## sets the unsigned integer value of `c`. `c` needs to represent an
|
||||||
|
## unsigned integer.
|
||||||
|
var t = skipRange(x.rawtype)
|
||||||
|
case t.kind:
|
||||||
|
of tyUInt: cast[ptr uint](x.value)[] = uint(y)
|
||||||
|
of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y)
|
||||||
|
of tyUInt16: cast[ptr uint16](x.value)[] = uint16(y)
|
||||||
|
of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
|
||||||
|
of tyUInt64: cast[ptr uint64](x.value)[] = uint64(y)
|
||||||
|
else: assert false
|
||||||
|
|
||||||
proc getChar*(x: TAny): char =
|
proc getChar*(x: TAny): char =
|
||||||
## retrieve the char value out of `x`. `x` needs to represent a char.
|
## retrieve the char value out of `x`. `x` needs to represent a char.
|
||||||
var t = skipRange(x.rawtype)
|
var t = skipRange(x.rawtype)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ type
|
||||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||||
|
|
||||||
TSqlQuery* = distinct string ## an SQL query string
|
TSqlQuery* = distinct string ## an SQL query string
|
||||||
|
TSqlPrepared* = distinct string ## a identifier for the prepared queries
|
||||||
|
|
||||||
FDb* = object of FIO ## effect that denotes a database operation
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
FReadDb* = object of FDB ## effect that denotes a read operation
|
FReadDb* = object of FDB ## effect that denotes a read operation
|
||||||
|
|
@ -33,7 +34,7 @@ proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||||
## on, later versions will check the string for valid syntax.
|
## on, later versions will check the string for valid syntax.
|
||||||
result = TSqlQuery(query)
|
result = TSqlQuery(query)
|
||||||
|
|
||||||
proc dbError(db: TDbConn) {.noreturn.} =
|
proc dbError*(db: TDbConn) {.noreturn.} =
|
||||||
## raises an EDb exception.
|
## raises an EDb exception.
|
||||||
var e: ref EDb
|
var e: ref EDb
|
||||||
new(e)
|
new(e)
|
||||||
|
|
@ -67,28 +68,57 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||||
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
var res = PQExec(db, q)
|
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||||
tags: [FReadDB, FWriteDb].} =
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query and raises EDB if not successful.
|
## executes the query and raises EDB if not successful.
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
var res = PQExec(db, q)
|
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
proc exec*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string]) {.tags: [FReadDB, FWriteDb].} =
|
||||||
|
var arr = allocCStringArray(args)
|
||||||
|
var res = PQexecPrepared(db, stmtName.string, int32(args.len), arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
proc newRow(L: int): TRow =
|
proc newRow(L: int): TRow =
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
for i in 0..L-1: result[i] = ""
|
for i in 0..L-1: result[i] = ""
|
||||||
|
|
||||||
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string]): PPGresult =
|
args: varargs[string]): PPGresult =
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
result = PQExec(db, q)
|
result = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
if PQresultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
||||||
|
|
||||||
|
proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string]): PPGresult =
|
||||||
|
var arr = allocCStringArray(args)
|
||||||
|
result = PQexecPrepared(db, stmtName.string, int32(args.len), arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
||||||
|
|
||||||
|
proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery;
|
||||||
|
nParams: int): TSqlPrepared =
|
||||||
|
var res = PQprepare(db, stmtName, query.string, int32(nParams), nil)
|
||||||
|
if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
|
return TSqlPrepared(stmtName)
|
||||||
|
|
||||||
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
|
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
|
||||||
for col in 0..cols-1:
|
for col in 0..cols-1:
|
||||||
|
|
@ -109,6 +139,17 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
yield result
|
yield result
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
|
## executes the prepared query and iterates over the result dataset.
|
||||||
|
var res = setupQuery(db, stmtName, args)
|
||||||
|
var L = PQnfields(res)
|
||||||
|
var result = newRow(L)
|
||||||
|
for i in 0..PQntuples(res)-1:
|
||||||
|
setRow(res, result, i, L)
|
||||||
|
yield result
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
proc getRow*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## retrieves a single row. If the query doesn't return any rows, this proc
|
## retrieves a single row. If the query doesn't return any rows, this proc
|
||||||
|
|
@ -119,6 +160,14 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
setRow(res, result, 0, L)
|
setRow(res, result, 0, L)
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
proc getRow*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
|
var res = setupQuery(db, stmtName, args)
|
||||||
|
var L = PQnfields(res)
|
||||||
|
result = newRow(L)
|
||||||
|
setRow(res, result, 0, L)
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
|
|
@ -126,6 +175,13 @@ proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
for r in FastRows(db, query, args):
|
for r in FastRows(db, query, args):
|
||||||
result.add(r)
|
result.add(r)
|
||||||
|
|
||||||
|
proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
|
## executes the prepared query and returns the whole result dataset.
|
||||||
|
result = @[]
|
||||||
|
for r in FastRows(db, stmtName, args):
|
||||||
|
result.add(r)
|
||||||
|
|
||||||
iterator rows*(db: TDbConn, query: TSqlQuery,
|
iterator rows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## same as `FastRows`, but slower and safe.
|
## same as `FastRows`, but slower and safe.
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ template `=~` *(s: string, pattern: TRegex): expr =
|
||||||
## echo("syntax error")
|
## echo("syntax error")
|
||||||
##
|
##
|
||||||
bind maxSubPatterns
|
bind maxSubPatterns
|
||||||
when not definedInScope(matches):
|
when not declaredInScope(matches):
|
||||||
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
||||||
match(s, pattern, matches)
|
match(s, pattern, matches)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||||
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
|
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
|
||||||
## may contain a path that will be created.
|
## may contain a path that will be created.
|
||||||
assert(z.mode != fmRead)
|
assert(z.mode != fmRead)
|
||||||
|
if not fileExists(src):
|
||||||
|
raise newException(EIO, "File '" & src & "' does not exist")
|
||||||
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
||||||
if zipsrc == nil:
|
if zipsrc == nil:
|
||||||
#echo("Dest: " & dest)
|
#echo("Dest: " & dest)
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,8 @@ struct TFrame {
|
||||||
NCSTRING procname;
|
NCSTRING procname;
|
||||||
NI line;
|
NI line;
|
||||||
NCSTRING filename;
|
NCSTRING filename;
|
||||||
NI len;
|
NI16 len;
|
||||||
|
NI16 calldepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define nimfr(proc, file) \
|
#define nimfr(proc, file) \
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const
|
||||||
"break", "case", "cast", "const", "continue", "converter", "discard",
|
"break", "case", "cast", "const", "continue", "converter", "discard",
|
||||||
"distinct", "div", "do", "elif", "else", "end", "enum", "except", "export",
|
"distinct", "div", "do", "elif", "else", "end", "enum", "except", "export",
|
||||||
"finally", "for", "from", "generic", "if", "import", "in", "include",
|
"finally", "for", "from", "generic", "if", "import", "in", "include",
|
||||||
"interface", "is", "isnot", "iterator", "lambda", "let", "macro", "method",
|
"interface", "is", "isnot", "iterator", "let", "macro", "method",
|
||||||
"mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc",
|
"mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc",
|
||||||
"ptr", "raise", "ref", "return", "shl", "shr", "static",
|
"ptr", "raise", "ref", "return", "shl", "shr", "static",
|
||||||
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
|
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
|
||||||
|
|
|
||||||
|
|
@ -775,7 +775,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||||
dispA(d.target, result, "<pre>", "\\begin{rstpre}\n", [])
|
dispA(d.target, result, "<pre>", "\\begin{rstpre}\n", [])
|
||||||
if lang == langNone:
|
if lang == langNone:
|
||||||
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, langstr)
|
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, langstr)
|
||||||
result.add(m.text)
|
for letter in m.text: escChar(d.target, result, letter)
|
||||||
else:
|
else:
|
||||||
var g: TGeneralTokenizer
|
var g: TGeneralTokenizer
|
||||||
initGeneralTokenizer(g, m.text)
|
initGeneralTokenizer(g, m.text)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue