mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 02:42:05 +00:00
Merge branch 'devel'
This commit is contained in:
@@ -1 +1 @@
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
@@ -263,7 +263,7 @@ type
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
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
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
@@ -291,6 +291,8 @@ const
|
||||
|
||||
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
||||
# require RC ops
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
@@ -417,6 +419,7 @@ type
|
||||
# efficiency
|
||||
nfTransf, # node has been transformed
|
||||
nfSem # node has been checked for semantics
|
||||
nfLL # node has gone through lambda lifting
|
||||
nfDotField # the call can use a dot operator
|
||||
nfDotSetter # the call can use a setter dot operarator
|
||||
nfExplicitCall # x.y() was used instead of x.y
|
||||
@@ -475,7 +478,7 @@ type
|
||||
# and first phase symbol lookup in generics
|
||||
skConditional, # symbol for the preprocessor (may become obsolete)
|
||||
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
|
||||
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
|
||||
skTemp, # a temporary variable (introduced by compiler)
|
||||
@@ -500,7 +503,8 @@ type
|
||||
skStub, # symbol is a stub and not yet loaded from the ROD
|
||||
# file (it is loaded on demand, which may
|
||||
# mean: never)
|
||||
skPackage # symbol is a package (used for canonicalization)
|
||||
skPackage, # symbol is a package (used for canonicalization)
|
||||
skAlias # an alias (needs to be resolved immediately)
|
||||
TSymKinds* = set[TSymKind]
|
||||
|
||||
const
|
||||
@@ -552,7 +556,7 @@ type
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||
mNewString, mNewStringOfCap,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mOrdinal,
|
||||
@@ -677,7 +681,7 @@ type
|
||||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||
# owns this location (required by GC algorithms
|
||||
# employing heap snapshots or sliding views)
|
||||
a*: int # location's "address", i.e. slot for temporaries
|
||||
a*: int
|
||||
|
||||
# ---------------- end of backend information ------------------------------
|
||||
|
||||
@@ -730,8 +734,9 @@ type
|
||||
# check for the owner when touching 'usedGenerics'.
|
||||
usedGenerics*: seq[PInstantiation]
|
||||
tab*: TStrTable # interface table for modules
|
||||
of skLet, skVar, skField:
|
||||
guard*: PSym
|
||||
else: nil
|
||||
|
||||
magic*: TMagic
|
||||
typ*: PType
|
||||
name*: PIdent
|
||||
@@ -784,12 +789,13 @@ type
|
||||
# the body of the user-defined type class
|
||||
# formal param list
|
||||
# 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
|
||||
sym*: PSym # types have the sym associated with them
|
||||
# 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
|
||||
# -1 means that the size is unkwown
|
||||
align*: int # the type's alignment requirements
|
||||
@@ -870,7 +876,7 @@ const
|
||||
tyProc, tyString, tyError}
|
||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
||||
skIterator, skClosureIterator,
|
||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||
nfDotSetter, nfDotField,
|
||||
nfIsRef}
|
||||
@@ -1160,7 +1166,6 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||
result.sons = @[name, pattern, genericParams, params,
|
||||
pragmas, exceptions, body]
|
||||
|
||||
|
||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
@@ -1170,8 +1175,8 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000 then
|
||||
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
#if result.id < 2000:
|
||||
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(a.k): a.k = b.k
|
||||
@@ -1189,6 +1194,7 @@ proc assignType(dest, src: PType) =
|
||||
dest.size = src.size
|
||||
dest.align = src.align
|
||||
dest.destructor = src.destructor
|
||||
dest.deepCopy = src.deepCopy
|
||||
# this fixes 'type TLock = TSysLock':
|
||||
if src.sym != nil:
|
||||
if dest.sym != nil:
|
||||
@@ -1226,6 +1232,8 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||
result.position = s.position
|
||||
result.loc = s.loc
|
||||
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 =
|
||||
result = newSym(s.kind, newIdent, s.owner, info)
|
||||
@@ -1310,6 +1318,10 @@ proc newSons(father: PNode, length: int) =
|
||||
setLen(father.sons, length)
|
||||
|
||||
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
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
@@ -1505,7 +1517,7 @@ proc isGenericRoutine*(s: PSym): bool =
|
||||
proc skipGenericOwner*(s: PSym): PSym =
|
||||
internalAssert s.kind in skProcKinds
|
||||
## Generic instantiations are owned by their originating generic
|
||||
## symbol. This proc skips such owners and goes straigh to the owner
|
||||
## symbol. This proc skips such owners and goes straight to the owner
|
||||
## of the generic itself (the module or the enclosing proc).
|
||||
result = if sfFromGeneric in s.flags: s.owner.owner
|
||||
else: s.owner
|
||||
|
||||
@@ -116,17 +116,16 @@ proc iiTablePut*(t: var TIITable, key, val: int)
|
||||
|
||||
# implementation
|
||||
|
||||
proc skipConv*(n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
result = n.sons[0]
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = n.sons[1]
|
||||
else: result = n
|
||||
|
||||
proc skipConvTakeType*(n: PNode): PNode =
|
||||
result = n.skipConv
|
||||
result.typ = n.typ
|
||||
proc skipConvAndClosure*(n: PNode): PNode =
|
||||
result = n
|
||||
while true:
|
||||
case result.kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
|
||||
nkClosure:
|
||||
result = result.sons[0]
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = result.sons[1]
|
||||
else: break
|
||||
|
||||
proc sameValue*(a, b: PNode): bool =
|
||||
result = false
|
||||
@@ -379,29 +378,30 @@ proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker = initIntSet()
|
||||
result = symToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope
|
||||
proc debugType(n: PType): PRope =
|
||||
proc debugTree(n: PNode, indent: int, maxRecDepth: int; renderType=false): PRope
|
||||
proc debugType(n: PType, maxRecDepth=100): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
else:
|
||||
else:
|
||||
result = toRope($n.kind)
|
||||
if n.sym != nil:
|
||||
app(result, " ")
|
||||
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, "(")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if i > 0: app(result, ", ")
|
||||
if n.sons[i] == nil:
|
||||
if n.sons[i] == nil:
|
||||
app(result, "null")
|
||||
else:
|
||||
app(result, debugType(n.sons[i]))
|
||||
if n.kind == tyObject and n.n != nil:
|
||||
else:
|
||||
app(result, debugType(n.sons[i], maxRecDepth-1))
|
||||
if n.kind == tyObject and n.n != nil:
|
||||
app(result, ", node: ")
|
||||
app(result, debugTree(n.n, 2, 100))
|
||||
app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
|
||||
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:
|
||||
result = toRope("null")
|
||||
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, symToYaml(n.sym, indent, maxRecDepth),
|
||||
# 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:
|
||||
if n.ident != nil:
|
||||
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):
|
||||
if i > 0: app(result, ",")
|
||||
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\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||
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:
|
||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||
# 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):
|
||||
# reset before pass as 'result' var:
|
||||
resetLoc(p, d)
|
||||
@@ -38,7 +38,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp)
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
app(pl, ~");$n")
|
||||
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:
|
||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||
# 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):
|
||||
# reset before pass as 'result' var:
|
||||
resetLoc(p, d)
|
||||
@@ -203,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genCallPattern()
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp)
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
genCallPattern()
|
||||
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:
|
||||
if d.k in {locTemp, locNone}:
|
||||
# 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, addrLoc(d))
|
||||
app(pl, ~"];$n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp)
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
app(pl, ~"];$n")
|
||||
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))
|
||||
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) =
|
||||
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)
|
||||
|
||||
proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
# XXX we don't generate keep alive info for now here
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
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)")
|
||||
else: unaryExpr(p, e, d, "$1Len0")
|
||||
of tyCString:
|
||||
useStringh(p.module)
|
||||
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
||||
else: unaryExpr(p, e, d, "strlen($1)")
|
||||
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 mSwap: genSwap(p, e, d)
|
||||
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)")
|
||||
of mPred:
|
||||
# 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)")
|
||||
of mSucc:
|
||||
# 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)")
|
||||
of mInc:
|
||||
if not (optOverflowCheck in p.options):
|
||||
if optOverflowCheck notin p.options:
|
||||
binaryStmt(p, e, d, "$1 += $2;$n")
|
||||
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
||||
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
|
||||
else:
|
||||
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
|
||||
of ast.mDec:
|
||||
if not (optOverflowCheck in p.options):
|
||||
if optOverflowCheck notin p.options:
|
||||
binaryStmt(p, e, d, "$1 -= $2;$n")
|
||||
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
|
||||
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
|
||||
@@ -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,
|
||||
mInSet:
|
||||
genSetOp(p, e, d, op)
|
||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit:
|
||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit,
|
||||
mParseBiggestFloat:
|
||||
var opr = e.sons[0].sym
|
||||
if lfNoDecl notin opr.loc.flags:
|
||||
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:
|
||||
let n = semparallel.liftParallel(p.module.module, e)
|
||||
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)
|
||||
|
||||
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:
|
||||
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
internalError(n.info, "expr: var not init " & sym.name.s)
|
||||
#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:
|
||||
accessThreadLocalVar(p, sym)
|
||||
if emulatedThreadVars():
|
||||
@@ -1888,11 +1922,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skTemp:
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
internalError(n.info, "expr: temp not init " & sym.name.s)
|
||||
#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)
|
||||
of skParam:
|
||||
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)
|
||||
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||
of nkNilLit:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -24,10 +24,29 @@ proc registerGcRoot(p: BProc, v: PSym) =
|
||||
linefmt(p.module.initProc, cpsStmts,
|
||||
"#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) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
||||
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)
|
||||
initLocExpr(p, n.sons[L-1], tup)
|
||||
var t = tup.t
|
||||
@@ -40,7 +59,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
registerGcRoot(p, v)
|
||||
else:
|
||||
assignLocalVar(p, v)
|
||||
initLocalVar(p, v, immediateAsgn=true)
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
|
||||
initLoc(field, locExpr, t.sons[i], tup.s)
|
||||
if t.kind == tyTuple:
|
||||
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)])
|
||||
|
||||
proc genVarPrototypeAux(m: BModule, sym: PSym)
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
var targetProc = p
|
||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||
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:
|
||||
# v.owner.kind != skModule:
|
||||
targetProc = p.module.preInitProc
|
||||
@@ -170,9 +193,9 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
registerGcRoot(p, v)
|
||||
else:
|
||||
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)
|
||||
loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
|
||||
|
||||
@@ -809,7 +832,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
discard cgsym(p.module, "E_Base")
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$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)
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
add(p.nestedTryStmts, t)
|
||||
|
||||
@@ -19,7 +19,7 @@ type
|
||||
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
|
||||
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) =
|
||||
if n == nil: return
|
||||
|
||||
@@ -122,6 +122,7 @@ proc mapSetType(typ: PType): TCTypeKind =
|
||||
else: result = ctArray
|
||||
|
||||
proc mapType(typ: PType): TCTypeKind =
|
||||
## Maps a nimrod type to a C type
|
||||
case typ.kind
|
||||
of tyNone, tyStmt: result = ctVoid
|
||||
of tyBool: result = ctBool
|
||||
@@ -453,7 +454,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
appf(result, " {$n", [name])
|
||||
|
||||
var desc = getRecordFields(m, typ, check)
|
||||
if (desc == nil) and not hasField:
|
||||
if desc == nil and not hasField:
|
||||
appf(result, "char dummy;$n", [])
|
||||
else:
|
||||
app(result, desc)
|
||||
@@ -722,7 +723,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
if objtype.sym == nil:
|
||||
internalError(d.info, "anonymous obj with discriminator")
|
||||
result = ropef("NimDT_$1_$2", [
|
||||
toRope(objtype.sym.name.s.mangle), toRope(d.name.s.mangle)])
|
||||
toRope(objtype.id), toRope(d.name.s.mangle)])
|
||||
|
||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
discard cgsym(m, "TNimNode")
|
||||
@@ -895,11 +896,20 @@ type
|
||||
|
||||
include ccgtrav
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
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 =
|
||||
let origType = t
|
||||
var t = getUniqueType(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
if containsOrIncl(m.typeInfoMarker, t.id):
|
||||
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
|
||||
if owner != m.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!
|
||||
genTupleInfo(m, t, result)
|
||||
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)
|
||||
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
|
||||
@@ -89,9 +89,15 @@ proc getUniqueType*(key: PType): PType =
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
||||
tyFromExpr, tyFieldAccessor:
|
||||
internalError("GetUniqueType")
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
|
||||
tyConst, tyIter, tyStatic:
|
||||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
of tyGenericInst, tyOrdinal, tyMutable, tyConst, tyIter, tyStatic:
|
||||
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,
|
||||
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||
@@ -124,7 +130,7 @@ proc getUniqueType*(key: PType): PType =
|
||||
if t != nil and sameType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
result = key
|
||||
of tyEnum:
|
||||
result = PType(idTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
|
||||
@@ -13,7 +13,7 @@ import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
options, intsets,
|
||||
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,
|
||||
semparallel
|
||||
|
||||
@@ -295,6 +295,7 @@ proc postStmtActions(p: BProc) {.inline.} =
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
|
||||
include "ccgtypes.nim"
|
||||
|
||||
@@ -398,7 +399,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
if not immediateAsgn:
|
||||
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)
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
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.s = OnStack
|
||||
result.flags = {}
|
||||
constructLoc(p, result, isTemp=true)
|
||||
constructLoc(p, result, not needsInit)
|
||||
|
||||
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
when false:
|
||||
@@ -574,7 +575,6 @@ proc fixLabel(p: BProc, labl: TLabel) =
|
||||
|
||||
proc genVarPrototype(m: BModule, sym: PSym)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
proc genStmts(p: BProc, t: PNode)
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
@@ -949,13 +949,23 @@ proc genFilenames(m: BModule): PRope =
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
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 =
|
||||
"\tsystemDatInit();$N" &
|
||||
"void PreMainInner() {$N" &
|
||||
"\tsystemInit();$N" &
|
||||
"$1" &
|
||||
"$2" &
|
||||
"$3" &
|
||||
"$4"
|
||||
"}$N$N" &
|
||||
"void PreMain() {$N" &
|
||||
"\tvoid (*volatile inner)();$N" &
|
||||
"\tsystemDatInit();$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$4" &
|
||||
"\t(*inner)();$N" &
|
||||
"}$N$N"
|
||||
|
||||
MainProcs =
|
||||
"\tNimMain();$N"
|
||||
@@ -964,9 +974,15 @@ proc genMainProc(m: BModule) =
|
||||
MainProcs & "\treturn nim_program_result;$N"
|
||||
|
||||
NimMainBody =
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"\tPreMain();$N" &
|
||||
"N_CDECL(void, NimMainInner)(void) {$N" &
|
||||
"$1" &
|
||||
"}$N$N" &
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"\tvoid (*volatile inner)();$N" &
|
||||
"\tPreMain();$N" &
|
||||
"\tinner = NimMainInner;$N" &
|
||||
"$2" &
|
||||
"\t(*inner)();$N" &
|
||||
"}$N$N"
|
||||
|
||||
PosixNimMain =
|
||||
@@ -1034,14 +1050,15 @@ proc genMainProc(m: BModule) =
|
||||
if optEndb in gOptions:
|
||||
gBreakpoints.app(m.genFilenames)
|
||||
|
||||
let initStackBottomCall = if emulatedThreadVars() or
|
||||
platform.targetOS == osStandalone: "".toRope
|
||||
else: ropecg(m, "\t#initStackBottom();$N")
|
||||
let initStackBottomCall =
|
||||
if emulatedThreadVars() or
|
||||
platform.targetOS == osStandalone: "".toRope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
|
||||
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
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:
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
|
||||
|
||||
@@ -80,9 +80,9 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
platform.OS[platform.hostOS].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:
|
||||
msgWriteln("git hash: " & gitHash)
|
||||
msgWriteln("git hash: " & gitHash)"""
|
||||
|
||||
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
||||
@@ -291,8 +291,12 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
lists.excludeStr(options.searchPaths, path)
|
||||
lists.excludeStr(options.lazyPaths, path)
|
||||
lists.excludePath(options.searchPaths, 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":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.nimcacheDir = processPath(arg)
|
||||
@@ -311,6 +315,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "undef", "u":
|
||||
expectArg(switch, arg, pass, info)
|
||||
undefSymbol(arg)
|
||||
of "symbol":
|
||||
expectArg(switch, arg, pass, info)
|
||||
declareSymbol(arg)
|
||||
of "compile":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: processCompile(arg)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
@@ -19,6 +19,9 @@ var gSymbols: PStringTable
|
||||
proc defineSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "true"
|
||||
|
||||
proc declareSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "unknown"
|
||||
|
||||
proc undefSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "false"
|
||||
|
||||
@@ -27,6 +30,7 @@ proc isDefined*(symbol: string): bool =
|
||||
result = gSymbols[symbol] == "true"
|
||||
|
||||
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
||||
proc isDeclared*(symbol: PIdent): bool = gSymbols.hasKey(symbol.s)
|
||||
|
||||
iterator definedSymbolNames*: string =
|
||||
for key, val in pairs(gSymbols):
|
||||
@@ -37,6 +41,38 @@ proc countDefinedSymbols*(): int =
|
||||
for key, val in pairs(gSymbols):
|
||||
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*() =
|
||||
gSymbols = newStringTable(modeStyleInsensitive)
|
||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
||||
@@ -50,8 +86,21 @@ proc initDefines*() =
|
||||
defineSymbol("nimunion")
|
||||
defineSymbol("nimnewshared")
|
||||
defineSymbol("nimrequiresnimframe")
|
||||
defineSymbol("nimparsebiggestfloatmagic")
|
||||
defineSymbol("nimalias")
|
||||
|
||||
# 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
|
||||
of cpuI386: defineSymbol("x86")
|
||||
of cpuIa64: defineSymbol("itanium")
|
||||
@@ -87,5 +136,10 @@ proc initDefines*() =
|
||||
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
|
||||
defineSymbol(CPU[targetCPU].name)
|
||||
defineSymbol(platform.OS[targetOS].name)
|
||||
declareSymbol("emulatedthreadvars")
|
||||
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
||||
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)
|
||||
if result != impUnknown: return result
|
||||
if sameTree(y, a):
|
||||
result = ple(m, x, b)
|
||||
result = ple(m, b, x)
|
||||
if result != impUnknown: return result
|
||||
|
||||
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
|
||||
|
||||
@@ -10,6 +10,25 @@
|
||||
# This is the JavaScript 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
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
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", [
|
||||
tmp, a.address, b.address])
|
||||
tmp = tmp2
|
||||
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1" |
|
||||
"local $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
|
||||
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||
"local $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
||||
|
||||
proc getFieldPosition(f: PNode): int =
|
||||
case f.kind
|
||||
@@ -881,14 +900,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
a, b: TCompRes
|
||||
first: BiggestInt
|
||||
r.typ = etyBaseIndex
|
||||
gen(p, n.sons[0], a)
|
||||
gen(p, n.sons[1], b)
|
||||
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
|
||||
gen(p, m.sons[0], a)
|
||||
gen(p, m.sons[1], b)
|
||||
internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
|
||||
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])
|
||||
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")
|
||||
r.res = ropef("chckIndx($1, $2, $3.length)-$2",
|
||||
[b.res, toRope(first), a.res])
|
||||
@@ -1321,7 +1341,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||
unaryExpr(p, n, r, "", "$1.length")
|
||||
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)")
|
||||
else:
|
||||
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 mSlurp, mStaticExec:
|
||||
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 mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
||||
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)
|
||||
of nkCharLit..nkInt64Lit:
|
||||
r.res = toRope(n.intVal)
|
||||
r.kind = resExpr
|
||||
of nkNilLit:
|
||||
if isEmptyType(n.typ):
|
||||
discard
|
||||
@@ -1539,8 +1560,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.typ = etyBaseIndex
|
||||
r.address = toRope"null" | toRope"nil"
|
||||
r.res = toRope"0"
|
||||
r.kind = resExpr
|
||||
else:
|
||||
r.res = toRope"null" | toRope"nil"
|
||||
r.kind = resExpr
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
||||
useMagic(p, "cstrToNimstr")
|
||||
@@ -1556,6 +1579,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if f > 0.0: r.res = toRope"Infinity"
|
||||
else: r.res = toRope"-Infinity"
|
||||
else: r.res = toRope(f.toStrMaxPrecision)
|
||||
r.kind = resExpr
|
||||
of nkCallKinds:
|
||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
||||
genMagic(p, n, r)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ type
|
||||
tkFinally, tkFor, tkFrom,
|
||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||
tkIs, tkIsnot, tkIterator,
|
||||
tkLambda, tkLet,
|
||||
tkLet,
|
||||
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
||||
tkObject, tkOf, tkOr, tkOut,
|
||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
|
||||
@@ -75,7 +75,7 @@ const
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "generic", "if",
|
||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||
"lambda", "let",
|
||||
"let",
|
||||
"macro", "method", "mixin", "mod",
|
||||
"nil", "not", "notin", "object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#
|
||||
|
||||
# This module implements a generic doubled linked list.
|
||||
|
||||
# TODO Remove this and replace it with something sensible
|
||||
import os
|
||||
type
|
||||
PListEntry* = ref TListEntry
|
||||
TListEntry* = object of TObject
|
||||
@@ -103,11 +104,12 @@ proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
|
||||
entry.next = list.head
|
||||
list.head = entry
|
||||
|
||||
proc excludeStr*(list: var TLinkedList, data: string) =
|
||||
proc excludePath*(list: var TLinkedList, data: string) =
|
||||
var it = list.head
|
||||
while it != nil:
|
||||
let nxt = it.next
|
||||
if PStrEntry(it).data == data: remove(list, it)
|
||||
if cmpPaths(PStrEntry(it).data, data) == 0:
|
||||
remove(list, it)
|
||||
it = nxt
|
||||
|
||||
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
||||
|
||||
@@ -77,7 +77,7 @@ proc llStreamClose(s: PLLStream) =
|
||||
of llsFile:
|
||||
close(s.f)
|
||||
|
||||
when not defined(readLineFromStdin):
|
||||
when not declared(readLineFromStdin):
|
||||
# fallback implementation:
|
||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||
stdout.write(prompt)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||
renderer, wordrecg, idgen
|
||||
renderer, wordrecg, idgen, nimfix.prettybase
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
||||
|
||||
@@ -40,11 +40,8 @@ proc considerQuotedIdent*(n: PNode): PIdent =
|
||||
template addSym*(scope: PScope, s: PSym) =
|
||||
strTableAdd(scope.symbols, s)
|
||||
|
||||
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
|
||||
if strTableIncl(scope.symbols, s):
|
||||
result = Failure
|
||||
else:
|
||||
result = Success
|
||||
proc addUniqueSym*(scope: PScope, s: PSym): bool =
|
||||
result = not strTableIncl(scope.symbols, s)
|
||||
|
||||
proc openScope*(c: PContext): PScope {.discardable.} =
|
||||
result = PScope(parent: c.currentScope,
|
||||
@@ -65,6 +62,17 @@ iterator walkScopes*(scope: PScope): PScope =
|
||||
yield current
|
||||
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 =
|
||||
result = strTableGet(c.currentScope.symbols, s)
|
||||
|
||||
@@ -139,14 +147,14 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
|
||||
localError(info, errAttemptToRedefine, s)
|
||||
|
||||
proc addDecl*(c: PContext, sym: PSym) =
|
||||
if c.currentScope.addUniqueSym(sym) == Failure:
|
||||
if not c.currentScope.addUniqueSym(sym):
|
||||
wrongRedefinition(sym.info, sym.name.s)
|
||||
|
||||
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
||||
discard c.currentScope.addUniqueSym(sym)
|
||||
|
||||
proc addDeclAt*(scope: PScope, sym: PSym) =
|
||||
if scope.addUniqueSym(sym) == Failure:
|
||||
if not scope.addUniqueSym(sym):
|
||||
wrongRedefinition(sym.info, sym.name.s)
|
||||
|
||||
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
@@ -163,7 +171,7 @@ proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
|
||||
if fn.kind notin OverloadableSyms:
|
||||
internalError(fn.info, "addOverloadableSymAt")
|
||||
return
|
||||
var check = strTableGet(scope.symbols, fn.name)
|
||||
let check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(fn.info, fn.name.s)
|
||||
else:
|
||||
@@ -179,20 +187,41 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addOverloadableSymAt(scope, 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 =
|
||||
# Looks up a symbol. Generates an error in case of nil.
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
result = searchInScopes(c, n.ident)
|
||||
if result == nil:
|
||||
result = searchInScopes(c, n.ident).skipAlias(n)
|
||||
if result == nil:
|
||||
fixSpelling(n, n.ident, searchInScopes)
|
||||
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||
result = errorSym(c, n)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
of nkAccQuoted:
|
||||
var ident = considerQuotedIdent(n)
|
||||
result = searchInScopes(c, ident)
|
||||
result = searchInScopes(c, ident).skipAlias(n)
|
||||
if result == nil:
|
||||
fixSpelling(n, ident, searchInScopes)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n)
|
||||
else:
|
||||
@@ -206,36 +235,38 @@ type
|
||||
TLookupFlag* = enum
|
||||
checkAmbiguity, checkUndeclared
|
||||
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var ident = considerQuotedIdent(n)
|
||||
result = searchInScopes(c, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
result = searchInScopes(c, ident).skipAlias(n)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
fixSpelling(n, ident, searchInScopes)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n)
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
contains(c.ambiguousSymbols, result.id):
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, ident.s)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
||||
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, n.sym.name.s)
|
||||
of nkDotExpr:
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
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
|
||||
if n.sons[1].kind == nkIdent:
|
||||
if n.sons[1].kind == nkIdent:
|
||||
ident = n.sons[1].ident
|
||||
elif n.sons[1].kind == nkAccQuoted:
|
||||
elif n.sons[1].kind == nkAccQuoted:
|
||||
ident = considerQuotedIdent(n.sons[1])
|
||||
if ident != nil:
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
result = strTableGet(m.tab, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
if ident != nil:
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
|
||||
else:
|
||||
result = strTableGet(m.tab, ident).skipAlias(n)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
fixSpelling(n.sons[1], ident, searchInScopes)
|
||||
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n.sons[1])
|
||||
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.mode = oimNoQualifier
|
||||
while true:
|
||||
result = initIdentIter(o.it, o.scope.symbols, ident)
|
||||
result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
|
||||
if result != nil:
|
||||
break
|
||||
else:
|
||||
@@ -277,11 +308,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if ident != nil:
|
||||
if o.m == c.module:
|
||||
# a module may access its private members:
|
||||
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
|
||||
result = initIdentIter(o.it, c.topLevelScope.symbols,
|
||||
ident).skipAlias(n)
|
||||
o.mode = oimSelfModule
|
||||
else:
|
||||
result = initIdentIter(o.it, o.m.tab, ident)
|
||||
else:
|
||||
else:
|
||||
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
|
||||
else:
|
||||
localError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
result = errorSym(c, n.sons[1])
|
||||
@@ -307,18 +339,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = nil
|
||||
of oimNoQualifier:
|
||||
if o.scope != nil:
|
||||
result = nextIdentIter(o.it, o.scope.symbols)
|
||||
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
|
||||
while result == nil:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
|
||||
result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
|
||||
# BUGFIX: o.it.name <-> n.ident
|
||||
else:
|
||||
result = nil
|
||||
of oimSelfModule:
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols)
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
|
||||
of oimOtherModule:
|
||||
result = nextIdentIter(o.it, o.m.tab)
|
||||
result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
|
||||
of oimSymChoice:
|
||||
if o.symChoiceIndex < sonsLen(n):
|
||||
result = n.sons[o.symChoiceIndex].sym
|
||||
@@ -329,31 +361,27 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.mode = oimSymChoiceLocalLookup
|
||||
o.scope = c.currentScope
|
||||
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:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
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:
|
||||
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
|
||||
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
|
||||
while result == nil:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
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)
|
||||
|
||||
when false:
|
||||
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
|
||||
flags = {checkUndeclared}): PSym =
|
||||
var o: TOverloadIter
|
||||
result = initOverloadIter(o, c, n)
|
||||
var a = result
|
||||
while a != nil:
|
||||
if sfImmediate in a.flags: return a
|
||||
a = nextOverloadIter(o, c, n)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
localError(n.info, errUndeclaredIdentifier, n.considerQuotedIdent.s)
|
||||
result = errorSym(c, n)
|
||||
proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
|
||||
flags: TSymFlags = {}): PSym =
|
||||
var o: TOverloadIter
|
||||
var a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind == kind and flags <= a.flags:
|
||||
return a
|
||||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
@@ -56,6 +56,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||
|
||||
result.add newAsgnStmt(newSymNode(temp), value)
|
||||
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))
|
||||
|
||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||
@@ -64,6 +65,22 @@ proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||
incl result.flags, tfFinal
|
||||
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) =
|
||||
# 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.
|
||||
@@ -74,6 +91,16 @@ proc addField*(obj: PType; s: PSym) =
|
||||
field.position = sonsLen(obj.n)
|
||||
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 =
|
||||
result = newNodeI(nkDotExpr, obj.info)
|
||||
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]
|
||||
if t == nil: break
|
||||
t = t.skipTypes(abstractInst)
|
||||
assert field != nil, b
|
||||
#if field == nil:
|
||||
# echo "FIELD ", b
|
||||
# debug deref.typ
|
||||
internalAssert field != nil
|
||||
addSon(deref, a)
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
addSon(result, deref)
|
||||
addSon(result, newSymNode(field))
|
||||
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 =
|
||||
# returns a[].b as a node
|
||||
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
|
||||
# - not in a parallel environment --> requires a flowVar for memory safety
|
||||
type
|
||||
TSpawnResult = enum
|
||||
TSpawnResult* = enum
|
||||
srVoid, srFlowVar, srByVar
|
||||
TFlowVarKind = enum
|
||||
fvInvalid # invalid type T for 'FlowVar[T]'
|
||||
fvGC # FlowVar of a GC'ed 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
|
||||
elif inParallel and not containsGarbageCollectedRef(t): srByVar
|
||||
else: srFlowVar
|
||||
@@ -161,7 +203,8 @@ proc flowVarKind(t: PType): TFlowVarKind =
|
||||
elif containsGarbageCollectedRef(t): fvInvalid
|
||||
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.typ = typ
|
||||
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)
|
||||
vpart.sons[0] = newSymNode(result)
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = v
|
||||
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
|
||||
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 """
|
||||
We generate roughly this:
|
||||
@@ -203,24 +252,24 @@ stmtList:
|
||||
"""
|
||||
|
||||
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||
varSection, call, barrier, fv: PNode;
|
||||
varSection, varInit, call, barrier, fv: PNode;
|
||||
spawnKind: TSpawnResult): PSym =
|
||||
var body = newNodeI(nkStmtList, f.info)
|
||||
var threadLocalBarrier: PSym
|
||||
if barrier != nil:
|
||||
var varSection = newNodeI(nkVarSection, barrier.info)
|
||||
threadLocalBarrier = addLocalVar(varSection, argsParam.owner,
|
||||
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
||||
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
|
||||
barrier.typ, barrier)
|
||||
body.add varSection
|
||||
body.add varSection2
|
||||
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
||||
var threadLocalProm: PSym
|
||||
if spawnKind == srByVar:
|
||||
threadLocalProm = addLocalVar(varSection, argsParam.owner, fv.typ, fv)
|
||||
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
||||
elif fv != nil:
|
||||
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 varInit
|
||||
if fv != nil and spawnKind != srByVar:
|
||||
# generate:
|
||||
# fv.owner = threadParam
|
||||
@@ -273,7 +322,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
|
||||
result.typ.rawAddSon(objType)
|
||||
|
||||
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 tmpName = getIdent(genPrefix)
|
||||
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)
|
||||
if i < formals.len and formals[i].typ.kind == tyVar:
|
||||
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
||||
elif containsTyRef(argType):
|
||||
localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
#elif containsTyRef(argType):
|
||||
# localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
|
||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||
var field = newSym(skField, fieldname, objType.owner, n.info)
|
||||
@@ -291,8 +341,8 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
|
||||
objType.addField(field)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||
|
||||
let temp = addLocalVar(varSection, objType.owner, argType,
|
||||
indirectAccess(castExpr, field, n.info))
|
||||
let temp = addLocalVar(varSection, varInit, objType.owner, argType,
|
||||
indirectAccess(castExpr, field, n.info))
|
||||
call.add(newSymNode(temp))
|
||||
|
||||
proc getRoot*(n: PNode): PSym =
|
||||
@@ -326,7 +376,8 @@ proc genHigh(n: PNode): PNode =
|
||||
result.sons[1] = n
|
||||
|
||||
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 tmpName = getIdent(genPrefix)
|
||||
# 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 argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
|
||||
abstractInst)
|
||||
if containsTyRef(argType):
|
||||
localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
#if containsTyRef(argType):
|
||||
# localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
|
||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||
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, 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))
|
||||
slice.sons[2] = threadLocal.newSymNode
|
||||
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:
|
||||
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))
|
||||
slice.sons[3] = threadLocal.newSymNode
|
||||
call.add slice
|
||||
@@ -387,7 +438,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||
field.typ = a.typ
|
||||
objType.addField(field)
|
||||
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))
|
||||
call.add(genDeref(threadLocal.newSymNode))
|
||||
else:
|
||||
@@ -395,7 +446,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||
field.typ = argType
|
||||
objType.addField(field)
|
||||
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))
|
||||
call.add(threadLocal.newSymNode)
|
||||
|
||||
@@ -463,10 +515,13 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||
|
||||
call.add(fn)
|
||||
var varSection = newNodeI(nkVarSection, n.info)
|
||||
var varInit = newNodeI(nkStmtList, n.info)
|
||||
if barrier.isNil:
|
||||
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, varSection, result)
|
||||
else:
|
||||
setupArgsForParallelism(n, objType, scratchObj, castExpr, call, varSection, result)
|
||||
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
|
||||
varSection, varInit, result)
|
||||
else:
|
||||
setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
|
||||
varSection, varInit, result)
|
||||
|
||||
var barrierAsExpr: PNode = nil
|
||||
if barrier != nil:
|
||||
@@ -498,7 +553,8 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
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)
|
||||
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
||||
genAddrOf(scratchObj.newSymNode))
|
||||
|
||||
@@ -27,6 +27,8 @@ var
|
||||
gSysTypes: array[TTypeKind, PType]
|
||||
compilerprocs: TStrTable
|
||||
|
||||
proc nilOrSysInt*: PType = gSysTypes[tyInt]
|
||||
|
||||
proc registerSysType(t: PType) =
|
||||
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]
|
||||
Name: "Nimrod"
|
||||
Version: "$version"
|
||||
@@ -34,11 +37,11 @@ Files: "config/nimdoc.cfg"
|
||||
Files: "config/nimdoc.tex.cfg"
|
||||
|
||||
[Documentation]
|
||||
Files: "doc/*.txt"
|
||||
Files: "doc/*.html"
|
||||
Files: "doc/*.cfg"
|
||||
Files: "doc/*.pdf"
|
||||
Files: "doc/*.ini"
|
||||
; Files: "doc/*.html"
|
||||
; Files: "doc/*.cfg"
|
||||
; Files: "doc/*.pdf"
|
||||
; Files: "doc/*.ini"
|
||||
Files: "doc/overview.html"
|
||||
Start: "doc/overview.html"
|
||||
|
||||
|
||||
@@ -61,13 +64,9 @@ Files: "compiler/readme.txt"
|
||||
Files: "compiler/nimrod.ini"
|
||||
Files: "compiler/nimrod.cfg"
|
||||
Files: "compiler/*.nim"
|
||||
Files: "compiler/c2nim/*.nim"
|
||||
Files: "compiler/c2nim/*.cfg"
|
||||
Files: "compiler/pas2nim/*.nim"
|
||||
Files: "compiler/pas2nim/*.cfg"
|
||||
|
||||
Files: "build/empty.txt"
|
||||
Files: "bin/empty.txt"
|
||||
Files: "doc/*.txt"
|
||||
Files: "compiler/nimfix/*.nim"
|
||||
Files: "compiler/nimfix/*.cfg"
|
||||
|
||||
|
||||
[Lib]
|
||||
@@ -115,17 +114,22 @@ Files: "examples/*.tmpl"
|
||||
|
||||
[Windows]
|
||||
Files: "bin/nimrod.exe"
|
||||
Files: "bin/nimrod_debug.exe"
|
||||
Files: "bin/c2nim.exe"
|
||||
Files: "bin/niminst.exe"
|
||||
Files: "bin/nimgrep.exe"
|
||||
|
||||
Files: "dist/*.dll"
|
||||
Files: "koch.exe"
|
||||
Files: "dist/mingw"
|
||||
; Files: "dist/mingw"
|
||||
Files: "start.bat"
|
||||
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]
|
||||
Files: "bin/nimrod"
|
||||
@@ -140,6 +144,9 @@ UninstallScript: "yes"
|
||||
path = r"c:\Program Files (x86)\Inno Setup 5\iscc.exe"
|
||||
flags = "/Q"
|
||||
|
||||
[NSIS]
|
||||
path = r"c:\Program Files (x86)\NSIS\makensis.exe"
|
||||
flags = "/V0"
|
||||
|
||||
[C_Compiler]
|
||||
path = r""
|
||||
|
||||
@@ -58,7 +58,7 @@ proc handleCmdLine() =
|
||||
if msgs.gErrorCounter == 0:
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
tccgen.run()
|
||||
tccgen.run(service.arguments)
|
||||
if optRun in gGlobalOptions:
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex: string
|
||||
@@ -79,7 +79,7 @@ proc handleCmdLine() =
|
||||
var ex = quoteShell(binPath)
|
||||
execExternalProgram(ex & ' ' & service.arguments)
|
||||
|
||||
when defined(GC_setMaxPause):
|
||||
when declared(GC_setMaxPause):
|
||||
GC_setMaxPause 2_000
|
||||
|
||||
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||
|
||||
@@ -14,7 +14,7 @@ const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
VersionMajor* = 0
|
||||
VersionMinor* = 9
|
||||
VersionPatch* = 5
|
||||
VersionPatch* = 6
|
||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||
|
||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||
|
||||
@@ -95,7 +95,7 @@ var
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||
optHints, optStackTrace, optLineTrace,
|
||||
optPatterns, optNilCheck}
|
||||
gGlobalOptions*: TGlobalOptions = {}
|
||||
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
||||
gExitcode*: int8
|
||||
gCmd*: TCommands = cmdNone # the command
|
||||
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
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
@@ -24,7 +24,8 @@ const
|
||||
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe}
|
||||
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
|
||||
wOverride}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
@@ -35,8 +36,8 @@ const
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wUses, wOperator, wGcSafe}
|
||||
exprPragmas* = {wLine}
|
||||
wTags, wLocks, wGcSafe}
|
||||
exprPragmas* = {wLine, wLocks}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||
@@ -44,27 +45,27 @@ const
|
||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||
wInjectStmt}
|
||||
wInjectStmt, wDeprecated}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||
wRaises, wUses, wTags, wGcSafe}
|
||||
wRaises, wLocks, wTags, wGcSafe}
|
||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError}
|
||||
wImportCpp, wImportObjC, wError, wGuard}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl}
|
||||
wGensym, wInject, wCodegenDecl, wGuard}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||
wThread, wRaises, wUses, wTags, wGcSafe}
|
||||
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||
|
||||
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, sfInfixCall)
|
||||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
|
||||
proc processImportObjC(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfNamedParamCall)
|
||||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToObjC)
|
||||
|
||||
proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
||||
result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
||||
@@ -513,27 +518,6 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||
else:
|
||||
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) =
|
||||
if n.kind == nkExprColonExpr:
|
||||
let it = n.sons[1]
|
||||
@@ -541,11 +525,50 @@ proc typeBorrow(sym: PSym, n: PNode) =
|
||||
localError(n.info, "a type can only borrow `.` for now")
|
||||
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,
|
||||
validPragmas: TSpecialWords): bool =
|
||||
var it = n.sons[i]
|
||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||
if key.kind == nkIdent:
|
||||
if key.kind == nkIdent:
|
||||
var userPragma = strTableGet(c.userPragmas, key.ident)
|
||||
if userPragma != nil:
|
||||
inc c.instCounter
|
||||
@@ -577,11 +600,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wAlign:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var align = expectIntLit(c, it)
|
||||
if not isPowerOfTwo(align) and align != 0:
|
||||
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.align = align
|
||||
of wSize:
|
||||
sym.typ.align = align.int16
|
||||
of wSize:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var size = expectIntLit(c, it)
|
||||
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
@@ -628,11 +651,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||
of wDestructor:
|
||||
if sym.typ.sons.len == 2:
|
||||
sym.flags.incl sfDestructor
|
||||
else:
|
||||
invalidPragma(it)
|
||||
of wNosideeffect:
|
||||
sym.flags.incl sfOverriden
|
||||
if sym.name.s.normalize != "destroy":
|
||||
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
|
||||
of wOverride:
|
||||
sym.flags.incl sfOverriden
|
||||
of wNosideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
@@ -646,17 +670,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerproc:
|
||||
noVal(it) # compilerproc may not get a string!
|
||||
if sfFromGeneric notin sym.flags:
|
||||
makeExternExport(sym, "$1", it.info)
|
||||
incl(sym.flags, sfCompilerProc)
|
||||
incl(sym.flags, sfUsed) # suppress all those stupid warnings
|
||||
registerCompilerProc(sym)
|
||||
of wProcVar:
|
||||
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||
of wProcVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfProcvar)
|
||||
of wDeprecated:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfDeprecated)
|
||||
of wDeprecated:
|
||||
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||
else: incl(c.module.flags, sfDeprecated)
|
||||
of wVarargs:
|
||||
noVal(it)
|
||||
@@ -787,10 +807,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
if sym == nil: invalidPragma(it)
|
||||
of wLine: pragmaLine(c, it)
|
||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||
of wUses: pragmaUses(c, it)
|
||||
of wOperator:
|
||||
if sym == nil: invalidPragma(it)
|
||||
else: sym.position = expectIntLit(c, it)
|
||||
of wGuard:
|
||||
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
|
||||
@@ -70,8 +70,15 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
var it: TIdentIter
|
||||
result = initIdentIter(it, scope.symbols, fn.name)
|
||||
while result != nil:
|
||||
if result.kind in skProcKinds and
|
||||
sameType(result.typ, fn.typ, flags): return
|
||||
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
||||
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)
|
||||
|
||||
|
||||
@@ -925,7 +925,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
|
||||
gsub(g, n.sons[0])
|
||||
of nkLambda:
|
||||
putWithSpace(g, tkLambda, "proc")
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
gsub(g, n.sons[paramsPos])
|
||||
gsub(g, n.sons[pragmasPos])
|
||||
put(g, tkSpaces, Space)
|
||||
|
||||
@@ -16,7 +16,7 @@ import
|
||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
|
||||
semparallel
|
||||
semparallel, lowerings
|
||||
|
||||
# implementation
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
if c.inCompilesContext > 0:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1))
|
||||
add(result, ')')
|
||||
|
||||
@@ -125,8 +125,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
# The destructor is either user-defined or automatically
|
||||
# generated by the compiler in a member-wise fashion.
|
||||
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
|
||||
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
|
||||
else: t
|
||||
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
|
||||
|
||||
if typeHoldingUserDefinition.destructor != nil:
|
||||
# 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
|
||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
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:
|
||||
# Consider::
|
||||
# const x = []
|
||||
@@ -184,13 +185,15 @@ proc isCastable(dst, src: PType): bool =
|
||||
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
|
||||
# tySequence, tyPointer, tyNil, tyOpenArray,
|
||||
# tyProc, tySet, tyEnum, tyBool, tyChar}
|
||||
if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
|
||||
return false
|
||||
var dstSize, srcSize: BiggestInt
|
||||
|
||||
dstSize = computeSize(dst)
|
||||
srcSize = computeSize(src)
|
||||
if dstSize < 0:
|
||||
result = false
|
||||
elif srcSize < 0:
|
||||
elif srcSize < 0:
|
||||
result = false
|
||||
elif not typeAllowed(dst, skParam):
|
||||
result = false
|
||||
@@ -198,6 +201,8 @@ proc isCastable(dst, src: PType): bool =
|
||||
result = (dstSize >= srcSize) or
|
||||
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
||||
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
|
||||
if result and src.kind == tyNil:
|
||||
result = dst.size <= platform.ptrSize
|
||||
|
||||
proc isSymChoice(n: PNode): bool {.inline.} =
|
||||
result = n.kind in nkSymChoices
|
||||
@@ -591,7 +596,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
const
|
||||
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
|
||||
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
|
||||
mAppendSeqElem, mNewSeq, mReset, mShallowCopy}
|
||||
mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
|
||||
|
||||
# get the real type of the callee
|
||||
# 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
|
||||
if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
|
||||
{sfForward, sfImportc} * callee.flags == {}:
|
||||
{sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
|
||||
if sfCompileTime notin callee.flags and
|
||||
optImplicitStatic notin gOptions: return
|
||||
|
||||
@@ -1369,20 +1374,19 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
|
||||
if onlyCurrentScope: return
|
||||
checkSonsLen(n, 2)
|
||||
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
|
||||
if (m != nil) and (m.kind == skModule):
|
||||
if (n.sons[1].kind == nkIdent):
|
||||
var ident = n.sons[1].ident
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
result = strTableGet(m.tab, ident)
|
||||
if m != nil and m.kind == skModule:
|
||||
let ident = considerQuotedIdent(n[1])
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
localError(n.sons[1].info, errIdentifierExpected, "")
|
||||
result = strTableGet(m.tab, ident)
|
||||
of nkAccQuoted:
|
||||
result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
else:
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = n.sons[0].sym
|
||||
else:
|
||||
localError(n.info, errIdentifierExpected, renderTree(n))
|
||||
result = nil
|
||||
|
||||
@@ -1390,10 +1394,16 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
|
||||
checkSonsLen(n, 2)
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
if lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
|
||||
result.intVal = 1
|
||||
elif not onlyCurrentScope and (n.sons[1].kind == nkIdent) and
|
||||
condsyms.isDefined(n.sons[1].ident):
|
||||
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
|
||||
elif not condsyms.isDeclared(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.info = n.info
|
||||
result.typ = getSysType(tyBool)
|
||||
@@ -1604,6 +1614,11 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
|
||||
initIdTable(bindings)
|
||||
bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
|
||||
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 =
|
||||
result = n
|
||||
@@ -1642,10 +1657,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = setMs(n, s)
|
||||
result.sons[1] = semExpr(c, n.sons[1])
|
||||
if not result[1].typ.isEmptyType:
|
||||
if c.inParallelStmt > 0:
|
||||
result.typ = result[1].typ
|
||||
else:
|
||||
if spawnResult(result[1].typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
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
|
||||
else: result = semDirectOp(c, n, flags)
|
||||
|
||||
@@ -1757,8 +1772,9 @@ proc checkPar(n: PNode): TParKind =
|
||||
var length = sonsLen(n)
|
||||
if length == 0:
|
||||
result = paTuplePositions # ()
|
||||
elif length == 1:
|
||||
result = paSingle # (expr)
|
||||
elif length == 1:
|
||||
if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
|
||||
else: result = paSingle # (expr)
|
||||
else:
|
||||
if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
|
||||
else: result = paTuplePositions
|
||||
|
||||
@@ -36,10 +36,11 @@ proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
template macroToExpand(s: expr): expr =
|
||||
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)
|
||||
case s.kind
|
||||
of skUnknown:
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
result = n
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
@@ -48,11 +49,13 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
@@ -80,7 +83,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
elif s.name.id in ctx:
|
||||
result = symChoice(c, n, s, scForceOpen)
|
||||
else:
|
||||
result = semGenericStmtSymbol(c, n, s)
|
||||
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||
# else: leave as nkIdent
|
||||
|
||||
proc newDot(n, b: PNode): PNode =
|
||||
@@ -95,8 +98,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
|
||||
var s = qualifiedLookUp(c, n, luf)
|
||||
if s != nil:
|
||||
result = semGenericStmtSymbol(c, n, s)
|
||||
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||
else:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
||||
result = n
|
||||
let n = n[1]
|
||||
let ident = considerQuotedIdent(n)
|
||||
@@ -107,7 +111,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
elif s.name.id in ctx:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
let sym = semGenericStmtSymbol(c, n, s)
|
||||
let sym = semGenericStmtSymbol(c, n, s, ctx)
|
||||
if sym.kind == nkSym:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
@@ -158,6 +162,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
result = n
|
||||
@@ -165,6 +170,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
result = n
|
||||
|
||||
@@ -33,7 +33,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||
t = errorType(c)
|
||||
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:
|
||||
#t = instGenericContainer(c, a, t)
|
||||
t = generateTypeInstance(c, pt, a, t)
|
||||
|
||||
@@ -126,7 +126,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result.typ = getSysType(tyString)
|
||||
of mInstantiationInfo: result = semInstantiationInfo(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 mNBindSym: result = semBindSym(c, n)
|
||||
of mLocals: result = semLocals(c, n)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
|
||||
renderer
|
||||
renderer, types
|
||||
from trees import getMagic
|
||||
from strutils import `%`
|
||||
|
||||
@@ -406,12 +406,17 @@ proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
|
||||
if result.isNil:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add n
|
||||
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
|
||||
it.sons[it.len-1] = emptyNode
|
||||
let t = b[1][0].typ.sons[0]
|
||||
if spawnResult(t, true) == srByVar:
|
||||
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
|
||||
it.sons[it.len-1] = emptyNode
|
||||
else:
|
||||
it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
|
||||
if result.isNil: result = n
|
||||
of nkAsgn, nkFastAsgn:
|
||||
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)
|
||||
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
|
||||
result = transformSpawnSons(owner, n, barrier)
|
||||
@@ -462,4 +467,3 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
|
||||
result.add callCodeGenProc("openBarrier", barrier)
|
||||
result.add transformSpawn(owner, body, barrier)
|
||||
result.add callCodeGenProc("closeBarrier", barrier)
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
a.addUse(copyNode(n))
|
||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||
tfGcSafe notin s.typ.flags:
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
a.gcUnsafe = true
|
||||
|
||||
type
|
||||
@@ -315,7 +315,6 @@ proc documentRaises*(n: PNode) =
|
||||
if n.sons[namePos].kind != nkSym: return
|
||||
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
||||
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
||||
documentEffect(n, n.sons[pragmasPos], wUses, usesEffects)
|
||||
|
||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||
|
||||
@@ -332,13 +331,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
mergeTags(tracked, tagSpec, n)
|
||||
|
||||
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
|
||||
|
||||
when trackGlobals:
|
||||
let usesSpec = effectSpec(pragma, wUses)
|
||||
mergeUses(tracked, usesSpec, n)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let n = n.skipConv
|
||||
if paramType != nil and tfNotNil in paramType.flags and
|
||||
@@ -358,7 +353,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
of impYes: discard
|
||||
|
||||
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:
|
||||
internalAssert op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
@@ -367,21 +362,24 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
propagateEffects(tracked, n, s.sym)
|
||||
elif effectList.len == 0:
|
||||
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)
|
||||
else:
|
||||
# we have no explicit effects so assume the worst:
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
||||
# assume GcUnsafe unless in its type:
|
||||
if notGcSafe(op):
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
tracked.gcUnsafe = true
|
||||
else:
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
||||
if notGcSafe(op):
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
tracked.gcUnsafe = true
|
||||
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 a.kind == nkSym and a.sym == tracked.owner:
|
||||
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]
|
||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
@@ -528,6 +523,11 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], 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))
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
# may not look like an assignment, but it is:
|
||||
@@ -636,10 +636,6 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||
if not isNil(tagsSpec):
|
||||
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
||||
"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):
|
||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
branch.name.s)
|
||||
@@ -651,16 +647,13 @@ proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||
let
|
||||
raisesSpec = effectSpec(n, wRaises)
|
||||
tagsSpec = effectSpec(n, wTags)
|
||||
usesSpec = effectSpec(n, wUses)
|
||||
if not isNil(raisesSpec) or not isNil(tagsSpec) or not isNil(usesSpec):
|
||||
if not isNil(raisesSpec) or not isNil(tagsSpec):
|
||||
internalAssert effects.len == 0
|
||||
newSeq(effects.sons, effectListLen)
|
||||
if not isNil(raisesSpec):
|
||||
effects.sons[exceptionEffects] = raisesSpec
|
||||
if not isNil(tagsSpec):
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
if not isNil(usesSpec):
|
||||
effects.sons[usesEffects] = usesSpec
|
||||
|
||||
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||
newSeq(effects.sons, effectListLen)
|
||||
@@ -705,16 +698,10 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
# after the check, use the formal spec:
|
||||
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 sfThread in s.flags and t.gcUnsafe:
|
||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
|
||||
@@ -22,20 +22,23 @@ proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
var s: PSym
|
||||
case n.sons[0].kind
|
||||
of nkIdent: s = lookUp(c, n.sons[0])
|
||||
of nkSym: s = n.sons[0].sym
|
||||
else: illFormedAst(n)
|
||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||
var x = newSymNode(s)
|
||||
x.info = n.info
|
||||
incl(s.flags, sfUsed)
|
||||
n.sons[0] = x
|
||||
suggestSym(x.info, s)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.kind != nkContinueStmt:
|
||||
var s: PSym
|
||||
case n.sons[0].kind
|
||||
of nkIdent: s = lookUp(c, n.sons[0])
|
||||
of nkSym: s = n.sons[0].sym
|
||||
else: illFormedAst(n)
|
||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||
var x = newSymNode(s)
|
||||
x.info = n.info
|
||||
incl(s.flags, sfUsed)
|
||||
n.sons[0] = x
|
||||
suggestSym(x.info, s)
|
||||
else:
|
||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||
else:
|
||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||
localError(n.info, errInvalidControlFlowX,
|
||||
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})
|
||||
var call = n.sons[length-2]
|
||||
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:
|
||||
result = semForVars(c, n)
|
||||
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)
|
||||
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
|
||||
TProcCompilationSteps = enum
|
||||
stepRegisterSymbol,
|
||||
@@ -1124,7 +1153,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
popOwner()
|
||||
pushOwner(s)
|
||||
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:
|
||||
# for DLL generation it is annoying to check for sfImportc!
|
||||
if sfBorrow in s.flags:
|
||||
|
||||
@@ -137,7 +137,7 @@ proc hasGenericArguments*(n: PNode): bool =
|
||||
return false
|
||||
|
||||
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
|
||||
# typedesc accepting proc. After generic param substitution, such procs
|
||||
# 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.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))
|
||||
if result == nil:
|
||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
||||
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:
|
||||
internalError(cl.info, "substitution with generic parameter")
|
||||
|
||||
@@ -353,7 +357,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
|
||||
of tyGenericBody:
|
||||
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
||||
result = t
|
||||
result = errorType(cl.c)
|
||||
#result = replaceTypeVarsT(cl, lastSon(t))
|
||||
|
||||
of tyFromExpr:
|
||||
|
||||
@@ -59,7 +59,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||
inc argsCount
|
||||
|
||||
if pass == passCmd2:
|
||||
if optRun notin gGlobalOptions and arguments != "":
|
||||
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
|
||||
rawMessage(errArgsNeedRunOption, [])
|
||||
|
||||
proc serve*(action: proc (){.nimcall.}) =
|
||||
|
||||
@@ -68,11 +68,9 @@ proc compileCCode*(ccode: string) =
|
||||
setupEnvironment()
|
||||
discard compileString(gTinyC, ccode)
|
||||
|
||||
proc run*() =
|
||||
var a: array[0..1, cstring]
|
||||
a[0] = ""
|
||||
a[1] = ""
|
||||
var err = tinyc.run(gTinyC, 0'i32, cast[cstringArray](addr(a))) != 0'i32
|
||||
proc run*(args: string) =
|
||||
var s = @[cstring(gProjectName)] & map(split(args), proc(x: string): cstring = cstring(x))
|
||||
var err = tinyc.run(gTinyC, cint(len(s)), cast[cstringArray](addr(s[0]))) != 0'i32
|
||||
closeCCState(gTinyC)
|
||||
if err: rawMessage(errExecutionOfProgramFailed, "")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
template tests*(body: stmt) {.immediate.} =
|
||||
when defined(selftest):
|
||||
when not defined(unittest): import unittest
|
||||
when not declared(unittest): import unittest
|
||||
body
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -13,7 +13,7 @@
|
||||
# * inlines iterators
|
||||
# * inlines constants
|
||||
# * performes constant folding
|
||||
# * converts "continue" to "break"
|
||||
# * converts "continue" to "break"; disambiguates "break"
|
||||
# * introduces method dispatchers
|
||||
# * performs lambda lifting for closure support
|
||||
|
||||
@@ -44,7 +44,6 @@ type
|
||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||
nestedProcs: int # > 0 if we are in a nested proc
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
inLoop: int # > 0 if we are in a loop
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
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.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 =
|
||||
var labl: PSym
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
@@ -213,14 +224,6 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
||||
discard c.breakSyms.pop
|
||||
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 =
|
||||
# What if it contains "continue" and "break"? "break" needs
|
||||
# an explicit label too, but not the same!
|
||||
@@ -239,6 +242,37 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
else:
|
||||
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) =
|
||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||
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 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
|
||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||
call.sons[0].sym.kind != skIterator):
|
||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||
return lambdalifting.liftForLoop(n).PTransNode
|
||||
#InternalError(call.info, "transformFor")
|
||||
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||
discard c.breakSyms.pop
|
||||
return result
|
||||
|
||||
#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])
|
||||
|
||||
result[1] = stmtList
|
||||
discard c.breakSyms.pop
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
for i in countup(0, length - 3):
|
||||
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
|
||||
# iterator!
|
||||
@@ -453,27 +499,32 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
||||
if arg.typ.kind == tyIter: continue
|
||||
case putArgInto(arg, formal.typ)
|
||||
of paDirectMapping:
|
||||
of paDirectMapping:
|
||||
idNodeTablePut(newC.mapping, formal, arg)
|
||||
of paFastAsgn:
|
||||
of paFastAsgn:
|
||||
# generate a temporary and produce an assignment statement:
|
||||
var temp = newTemp(c, formal.typ, formal.info)
|
||||
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))
|
||||
of paVarAsgn:
|
||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||
idNodeTablePut(newC.mapping, formal, arg)
|
||||
# XXX BUG still not correct if the arg has a side effect!
|
||||
var body = iter.getBody
|
||||
var body = iter.getBody.copyTree
|
||||
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)
|
||||
add(result, transform(c, body))
|
||||
#findWrongOwners(c, result.pnode)
|
||||
add(stmtList, transform(c, body))
|
||||
#findWrongOwners(c, stmtList.pnode)
|
||||
dec(c.inlining)
|
||||
popInfoContext()
|
||||
popTransCon(c)
|
||||
# echo "transformed: ", result.PNode.renderTree
|
||||
# echo "transformed: ", stmtList.PNode.renderTree
|
||||
|
||||
proc getMagicOp(call: PNode): TMagic =
|
||||
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)
|
||||
result = PTransNode(n)
|
||||
of nkForStmt:
|
||||
inc c.inLoop
|
||||
result = transformFor(c, n)
|
||||
dec c.inLoop
|
||||
of nkParForStmt:
|
||||
inc c.inLoop
|
||||
result = transformSons(c, n)
|
||||
dec c.inLoop
|
||||
of nkCaseStmt: result = transformCase(c, n)
|
||||
of nkContinueStmt:
|
||||
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
||||
var labl = c.contSyms[c.contSyms.high]
|
||||
add(result, PTransNode(newSymNode(labl)))
|
||||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkWhileStmt:
|
||||
inc c.inLoop
|
||||
result = newTransNode(n)
|
||||
result[0] = transform(c, n.sons[0])
|
||||
result[1] = transformLoopBody(c, n.sons[1])
|
||||
dec c.inLoop
|
||||
of nkWhileStmt: result = transformWhile(c, n)
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
result = transformCall(c, n)
|
||||
@@ -740,6 +782,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||
# result = lambdalifting.liftIterator(prc, result)
|
||||
incl(result.flags, nfTransf)
|
||||
when useEffectSystem: trackProc(prc, result)
|
||||
if prc.name.s == "testbody":
|
||||
echo renderTree(result)
|
||||
|
||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
|
||||
@@ -99,7 +99,7 @@ proc isPureObject(typ: PType): bool =
|
||||
|
||||
proc getOrdValue(n: PNode): BiggestInt =
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit: result = n.intVal
|
||||
of nkCharLit..nkUInt64Lit: result = n.intVal
|
||||
of nkNilLit: result = 0
|
||||
of nkHiddenStdConv: result = getOrdValue(n.sons[1])
|
||||
else:
|
||||
@@ -582,7 +582,10 @@ proc firstOrd(t: PType): BiggestInt =
|
||||
of tyGenericInst, tyDistinct, tyConst, tyMutable,
|
||||
tyTypeDesc, tyFieldAccessor:
|
||||
result = firstOrd(lastSon(t))
|
||||
else:
|
||||
of tyOrdinal:
|
||||
if t.len > 0: result = firstOrd(lastSon(t))
|
||||
else: internalError("invalid kind for first(" & $t.kind & ')')
|
||||
else:
|
||||
internalError("invalid kind for first(" & $t.kind & ')')
|
||||
result = 0
|
||||
|
||||
@@ -617,7 +620,10 @@ proc lastOrd(t: PType): BiggestInt =
|
||||
tyTypeDesc, tyFieldAccessor:
|
||||
result = lastOrd(lastSon(t))
|
||||
of tyProxy: result = 0
|
||||
else:
|
||||
of tyOrdinal:
|
||||
if t.len > 0: result = lastOrd(lastSon(t))
|
||||
else: internalError("invalid kind for last(" & $t.kind & ')')
|
||||
else:
|
||||
internalError("invalid kind for last(" & $t.kind & ')')
|
||||
result = 0
|
||||
|
||||
@@ -907,9 +913,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
result = sameTypeAux(a.sons[0], b.sons[0], c)
|
||||
else:
|
||||
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
|
||||
result = a.id == b.id and sameFlags(a, b)
|
||||
of tyError:
|
||||
result = b.kind == tyError
|
||||
of tyTuple:
|
||||
cycleCheck()
|
||||
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]):
|
||||
return true
|
||||
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
|
||||
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 evaltempl import evalTemplate
|
||||
@@ -87,9 +87,7 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
|
||||
when not defined(nimComputedGoto):
|
||||
{.pragma: computedGoto.}
|
||||
|
||||
proc myreset(n: var TFullReg) =
|
||||
when defined(system.reset):
|
||||
reset(n)
|
||||
proc myreset(n: var TFullReg) = reset(n)
|
||||
|
||||
template ensureKind(k: expr) {.immediate, dirty.} =
|
||||
if regs[ra].kind != k:
|
||||
@@ -776,6 +774,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = substr(regs[rb].node.strVal,
|
||||
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:
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
@@ -1068,6 +1078,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNKind:
|
||||
decodeB(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].node.kind)
|
||||
c.comesFromHeuristic = regs[rb].node.info
|
||||
of opcNIntVal:
|
||||
decodeB(rkInt)
|
||||
let a = regs[rb].node
|
||||
@@ -1243,8 +1254,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
internalError(c.debug[pc],
|
||||
"request to create a NimNode of invalid kind")
|
||||
let cc = regs[rc].node
|
||||
|
||||
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
|
||||
of opcNCopyNimNode:
|
||||
decodeB(rkNode)
|
||||
|
||||
@@ -66,7 +66,7 @@ type
|
||||
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcSwap, opcIsNil, opcOf, opcIs,
|
||||
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
||||
opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
|
||||
opcNarrowS, opcNarrowU,
|
||||
|
||||
opcAddStrCh,
|
||||
@@ -188,6 +188,7 @@ type
|
||||
features*: TSandboxFlags
|
||||
traceActive*: bool
|
||||
loopIterations*: int
|
||||
comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
|
||||
|
||||
TPosition* = distinct int
|
||||
|
||||
@@ -196,7 +197,8 @@ type
|
||||
proc newCtx*(module: PSym): PCtx =
|
||||
PCtx(code: @[], debug: @[],
|
||||
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) =
|
||||
c.module = module
|
||||
|
||||
@@ -12,11 +12,11 @@ import ast, types, msgs, osproc, streams, options
|
||||
proc readOutput(p: PProcess): string =
|
||||
result = ""
|
||||
var output = p.outputStream
|
||||
discard p.waitForExit
|
||||
while not output.atEnd:
|
||||
result.add(output.readLine)
|
||||
result.add("\n")
|
||||
result.setLen(result.len - "\n".len)
|
||||
discard p.waitForExit
|
||||
|
||||
proc opGorge*(cmd, input: string): string =
|
||||
var p = startCmd(cmd)
|
||||
|
||||
@@ -43,18 +43,19 @@ type
|
||||
proc debugInfo(info: TLineInfo): string =
|
||||
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:
|
||||
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]
|
||||
if x.opcode in relativeJumps:
|
||||
jumpTargets.incl(i+x.regBx-wordExcess)
|
||||
|
||||
# for debugging purposes
|
||||
var i = start
|
||||
while i < c.code.len:
|
||||
while i <= last:
|
||||
if i in jumpTargets: result.addf("L$1:\n", i)
|
||||
let x = c.code[i]
|
||||
|
||||
@@ -82,9 +83,9 @@ proc codeListing(c: PCtx, result: var string, start=0) =
|
||||
result.add("\n")
|
||||
inc i
|
||||
|
||||
proc echoCode*(c: PCtx, start=0) {.deprecated.} =
|
||||
proc echoCode*(c: PCtx, start=0; last = -1) {.deprecated.} =
|
||||
var buf = ""
|
||||
codeListing(c, buf, start)
|
||||
codeListing(c, buf, start, last)
|
||||
echo buf
|
||||
|
||||
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)
|
||||
|
||||
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 =
|
||||
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
|
||||
@@ -637,8 +639,10 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
var x = n.sons[1]
|
||||
if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0]
|
||||
let
|
||||
dest = c.genx(n.sons[1], {gfAddrOf})
|
||||
dest = c.genx(x)
|
||||
tmp = c.genx(n.sons[2])
|
||||
c.gABC(n, opc, dest, tmp, 0)
|
||||
#c.genAsgnPatch(n.sons[1], dest)
|
||||
@@ -852,6 +856,24 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.freeTemp(tmp1)
|
||||
c.freeTemp(tmp2)
|
||||
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:
|
||||
unused(n, dest)
|
||||
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.
|
||||
if not isAddr and unneededIndirection(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, newflags)
|
||||
elif isAddr and isGlobal(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, flags+{gfAddrOf})
|
||||
else:
|
||||
let tmp = c.genx(n.sons[0], newflags)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -1075,6 +1099,8 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||
# XXX generate type initialization here?
|
||||
if v.position == 0:
|
||||
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
|
||||
c.prc.slots[v.position] = (inUse: true,
|
||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||
@@ -1098,10 +1124,9 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
# we need to ensure that we don't evaluate 'x' here:
|
||||
# proc foo() = var x ...
|
||||
let s = n.sym
|
||||
if s.position == 0:
|
||||
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
||||
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
|
||||
cannotEval(n)
|
||||
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
||||
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
|
||||
cannotEval(n)
|
||||
|
||||
proc isTemp(c: PCtx; dest: TDest): bool =
|
||||
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
|
||||
@@ -1228,6 +1253,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
c.gABx(n, opcLdGlobal, cc, s.position)
|
||||
c.gABC(n, opcNodeToReg, dest, cc)
|
||||
c.freeTemp(cc)
|
||||
elif gfAddrOf in flags:
|
||||
c.gABx(n, opcLdGlobalAddr, dest, s.position)
|
||||
else:
|
||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||
else:
|
||||
|
||||
@@ -27,7 +27,7 @@ type
|
||||
wContinue, wConverter, wDiscard, wDistinct, wDiv, wDo,
|
||||
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
||||
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,
|
||||
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
|
||||
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
|
||||
@@ -39,7 +39,7 @@ type
|
||||
|
||||
wDestroy,
|
||||
|
||||
wImmediate, wDestructor, wDelegator,
|
||||
wImmediate, wDestructor, wDelegator, wOverride,
|
||||
wImportCpp, wImportObjC,
|
||||
wImportCompilerProc,
|
||||
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
||||
@@ -64,7 +64,7 @@ type
|
||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||
wAsmNoStackFrame,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wUses,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
|
||||
|
||||
wAuto, wBool, wCatch, wChar, wClass,
|
||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||
@@ -107,7 +107,7 @@ const
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "generic", "if",
|
||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||
"lambda", "let",
|
||||
"let",
|
||||
"macro", "method", "mixin", "mod", "nil", "not", "notin",
|
||||
"object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
@@ -122,7 +122,7 @@ const
|
||||
|
||||
"destroy",
|
||||
|
||||
"immediate", "destructor", "delegator",
|
||||
"immediate", "destructor", "delegator", "override",
|
||||
"importcpp", "importobjc",
|
||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
||||
@@ -147,7 +147,7 @@ const
|
||||
"computedgoto", "injectstmt",
|
||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||
"guard", "uses",
|
||||
"guard", "locks",
|
||||
|
||||
"auto", "bool", "catch", "char", "class",
|
||||
"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.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"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
===============================================================================
|
||||
Nimrod -- a Compiler for Nimrod. http://nimrod-code.org/
|
||||
|
||||
Copyright (C) 2004-2014 Andreas Rumpf. All rights reserved.
|
||||
=====================================================
|
||||
Nimrod -- a Compiler for Nimrod. http://nimrod-lang.org/
|
||||
|
||||
Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -12,6 +12,7 @@ Advanced commands:
|
||||
module dependency graph
|
||||
//dump dump all defined conditionals and search paths
|
||||
//check checks the project for syntax and semantic
|
||||
//pretty homogenizes source code style
|
||||
//idetools compiler support for IDEs: possible options:
|
||||
--track:FILE,LINE,COL track a file/cursor position
|
||||
--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.
|
||||
|
||||
|
||||
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
|
||||
=================
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ Options:
|
||||
-p, --path:PATH add path to search paths
|
||||
-d, --define:SYMBOL define a conditional symbol
|
||||
-u, --undef:SYMBOL undefine a conditional symbol
|
||||
--symbol:SYMBOL declare a conditional symbol
|
||||
-f, --forceBuild force rebuilding of all modules
|
||||
--stackTrace:on|off turn stack 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
|
||||
--advanced show advanced command line switches
|
||||
-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
|
||||
generic
|
||||
if import in include interface is isnot iterator
|
||||
lambda let
|
||||
let
|
||||
macro method mixin mod
|
||||
nil not notin
|
||||
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
|
||||
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
|
||||
-----------
|
||||
|
||||
|
||||
17
doc/lib.txt
17
doc/lib.txt
@@ -56,7 +56,10 @@ Core
|
||||
|
||||
* `typeinfo <typeinfo.html>`_
|
||||
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>`_
|
||||
Actor support for Nimrod; implemented as a layer on top of the threads and
|
||||
channels modules.
|
||||
@@ -447,10 +450,6 @@ Other
|
||||
This module contains code for reading from `stdin`:idx:. On UNIX the GNU
|
||||
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
|
||||
========
|
||||
@@ -463,8 +462,6 @@ Windows specific
|
||||
|
||||
* `windows <windows.html>`_
|
||||
Contains a wrapper for the Win32 API.
|
||||
* `ole2 <ole2.html>`_
|
||||
Contains GUIDs for OLE2 automation support.
|
||||
* `shellapi <shellapi.html>`_
|
||||
Contains a wrapper for the ``shellapi.h`` header.
|
||||
* `shfolder <shfolder.html>`_
|
||||
@@ -594,7 +591,8 @@ compiler.
|
||||
|
||||
.. 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
|
||||
-------------------
|
||||
@@ -605,7 +603,8 @@ Nimrod programming language.
|
||||
|
||||
.. 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="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
|
||||
--------
|
||||
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
|
||||
---------------------------
|
||||
@@ -1451,7 +1421,7 @@ Examples:
|
||||
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
|
||||
@@ -2497,7 +2467,7 @@ variable to use:
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
to previously undeclared symbol names. They can be used to provide a
|
||||
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.
|
||||
|
||||
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 `.()`
|
||||
---------------
|
||||
This operator will be matched exclusively against method calls. It has higher
|
||||
precedence than the `.` operator and this allows you to handle expressions like
|
||||
`x.y` and `x.y()` differently if you are interfacing with a scripting language
|
||||
precedence than the `.` operator and this allows one to handle expressions like
|
||||
`x.y` and `x.y()` differently if one is interfacing with a scripting language
|
||||
for example.
|
||||
|
||||
operator `.=`
|
||||
@@ -4391,6 +4361,117 @@ This operator will be matched against assignments to missing fields.
|
||||
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
|
||||
=====================
|
||||
|
||||
@@ -4960,6 +5041,27 @@ first implementation to play with a language feature before a nicer syntax
|
||||
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
|
||||
-------------------
|
||||
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
|
||||
verify this.
|
||||
|
||||
As a special semantic rule, the built-in ``debugEcho`` pretends to be free of
|
||||
side effects, so that it can be used for debugging routines marked as
|
||||
``noSideEffect``.
|
||||
As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
|
||||
pretends to be free of side effects, so that it can be used for debugging
|
||||
routines marked as ``noSideEffect``.
|
||||
|
||||
**Future directions**: ``func`` may become a keyword and syntactic sugar for a
|
||||
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 proc must have a single parameter with a concrete type (the name of a
|
||||
generic type is allowed too).
|
||||
Its usage is deprecated, use the ``override`` pragma instead.
|
||||
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
|
||||
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``.
|
||||
override pragma
|
||||
---------------
|
||||
|
||||
See `type bound operations`_ instead.
|
||||
|
||||
procvar pragma
|
||||
--------------
|
||||
@@ -5290,7 +5344,7 @@ See `Ordinary vs immediate templates`_.
|
||||
compilation option pragmas
|
||||
--------------------------
|
||||
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
|
||||
others may be added later).
|
||||
@@ -5490,10 +5544,10 @@ spelled*:
|
||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||
|
||||
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++
|
||||
you can use the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and
|
||||
the same feature under the same name. Also, if one is interfacing with C++
|
||||
the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and
|
||||
interfacing with Objective-C the `ImportObjC pragma
|
||||
<nimrodc.html#importobjc-pragma>`_.
|
||||
<nimrodc.html#importobjc-pragma>`_ can be used.
|
||||
|
||||
|
||||
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:
|
||||
|
||||
* It must be a call expresion ``f(a, ...)``.
|
||||
* It must be a call expression ``f(a, ...)``.
|
||||
* ``f`` must be ``gcsafe``.
|
||||
* ``f`` must not have the calling convention ``closure``.
|
||||
* ``f``'s parameters may not be of type ``var`` nor may they contain ``ref``.
|
||||
This means you have to use raw ``ptr``'s for data passing reminding the
|
||||
* ``f``'s parameters may not be of type ``var``.
|
||||
This means one has to use raw ``ptr``'s for data passing reminding the
|
||||
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``
|
||||
needs to be used. Other means will be provided soon.
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ customize this style sheet.
|
||||
Andreas Rumpf
|
||||
*/
|
||||
|
||||
body {
|
||||
color: black;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
@@ -152,10 +152,12 @@ the first matching file is used.
|
||||
|
||||
Generated C code directory
|
||||
--------------------------
|
||||
The generated files that Nimrod produces all go into a subdirectory called
|
||||
``nimcache`` in your project directory. This makes it easy to delete all
|
||||
generated files.
|
||||
|
||||
The generated files that Nimrod produces all go into a subdirectory called
|
||||
``nimcache`` in your project directory. This makes it easy to delete all
|
||||
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
|
||||
Linux does not compile on Windows, for instance. The comment on top of the
|
||||
C file lists the OS, CPU and CC the file has been compiled for.
|
||||
@@ -540,6 +542,58 @@ in C/C++).
|
||||
**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
|
||||
==============
|
||||
|
||||
|
||||
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.
|
||||
* 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
|
||||
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
|
||||
proc (``spawn f(loc)``) has to be immutable for the duration of
|
||||
the ``parallel`` section. This is called the *immutability check*. Currently
|
||||
it is not specified what exactly "complex location" means. We need to make
|
||||
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*.
|
||||
* Slices are optimized so that no copy is performed. This optimization is not
|
||||
yet performed for ordinary slices outside of a ``parallel`` section. Slices
|
||||
|
||||
240
doc/tut1.txt
240
doc/tut1.txt
@@ -17,10 +17,9 @@ Introduction
|
||||
|
||||
|
||||
This document is a tutorial for the programming language *Nimrod*.
|
||||
This tutorial assumes that you are familiar with basic programming concepts
|
||||
like variables, types or statements but is kept very basic. The manual
|
||||
contains many more examples of the advanced language features.
|
||||
|
||||
This tutorial assumes that you are familiar with basic programming concepts
|
||||
like variables, types or statements but is kept very basic. The `manual
|
||||
<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
|
||||
|
||||
With the ``--run`` switch Nimrod executes the file automatically
|
||||
after compilation. You can give your program command line arguments by
|
||||
appending them after the filename::
|
||||
With the ``--run`` `switch <nimrodc.html#command-line-switches>`_ Nimrod
|
||||
executes the file automatically after compilation. You can give your program
|
||||
command line arguments by appending them after the filename::
|
||||
|
||||
nimrod compile --run greetings.nim arg1 arg2
|
||||
|
||||
@@ -54,9 +53,10 @@ To compile a release version use::
|
||||
|
||||
nimrod c -d:release greetings.nim
|
||||
|
||||
By default the Nimrod compiler generates a large amount of runtime checks
|
||||
aiming for your debugging pleasure. With ``-d:release`` these checks are
|
||||
turned off and optimizations are turned on.
|
||||
By default the Nimrod compiler generates a large amount of runtime checks
|
||||
aiming for your debugging pleasure. With ``-d:release`` these checks are
|
||||
`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
|
||||
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
|
||||
a new variable named ``name`` of type ``string`` with the value that is
|
||||
returned by the ``readLine`` procedure. Since the compiler knows that
|
||||
``readLine`` returns a string, you can leave out the type in the declaration
|
||||
(this is called `local type inference`:idx:). So this will work too:
|
||||
returned by the `readLine <system.html#readLine,TFile>`_ procedure. Since the
|
||||
compiler knows that `readLine <system.html#readLine,TFile>`_ returns a string,
|
||||
you can leave out the type in the declaration (this is called `local type
|
||||
inference`:idx:). So this will work too:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
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
|
||||
Nimrod: it is a good compromise between brevity and readability.
|
||||
|
||||
The "hello world" program contains several identifiers that are already
|
||||
known to the compiler: ``echo``, ``readLine``, etc. These built-ins are
|
||||
declared in the system_ module which is implicitly imported by any other
|
||||
module.
|
||||
The "hello world" program contains several identifiers that are already known
|
||||
to the compiler: ``echo``, `readLine <system.html#readLine,TFile>`_, etc.
|
||||
These built-ins are declared in the system_ module which is implicitly
|
||||
imported by any other module.
|
||||
|
||||
|
||||
Lexical elements
|
||||
@@ -154,11 +155,11 @@ the syntax, watch their indentation:
|
||||
when false:
|
||||
brokenCode()
|
||||
|
||||
Another option is to use the `discard`_ statement together with
|
||||
*long string literals* to create block comments:
|
||||
Another option is to use the `discard statement`_ together with *long string
|
||||
literals* to create block comments:
|
||||
|
||||
.. 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.
|
||||
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":
|
||||
|
||||
.. code-block::
|
||||
const input = readline(stdin) # Error: constant expression expected
|
||||
const input = readLine(stdin) # Error: constant expression expected
|
||||
|
||||
.. code-block::
|
||||
let input = readline(stdin) # works
|
||||
let input = readLine(stdin) # works
|
||||
|
||||
|
||||
Control flow statements
|
||||
@@ -285,9 +286,10 @@ The if statement is one way to branch the control flow:
|
||||
else:
|
||||
echo("Hi, ", name, "!")
|
||||
|
||||
There can be zero or more elif parts, and the else part is optional. The
|
||||
keyword ``elif`` is short for ``else if``, and is useful to avoid excessive
|
||||
indentation. (The ``""`` is the empty string. It contains no characters.)
|
||||
There can be zero or more ``elif`` parts, and the ``else`` part is optional.
|
||||
The keyword ``elif`` is short for ``else if``, and is useful to avoid
|
||||
excessive indentation. (The ``""`` is the empty string. It contains no
|
||||
characters.)
|
||||
|
||||
|
||||
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")
|
||||
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
|
||||
disappears. Note that it is impossible to cover all possible string values:
|
||||
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*
|
||||
provides. The example uses the built-in ``countup`` iterator:
|
||||
provides. The example uses the built-in `countup <system.html#countup>`_
|
||||
iterator:
|
||||
|
||||
.. code-block:: nimrod
|
||||
echo("Counting to ten: ")
|
||||
@@ -378,11 +381,11 @@ provides. The example uses the built-in ``countup`` iterator:
|
||||
echo($i)
|
||||
# --> 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
|
||||
into a string. The variable ``i`` is implicitly declared by the ``for`` loop
|
||||
and has the type ``int``, because that is what ``countup`` returns. ``i`` runs
|
||||
through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
||||
the same:
|
||||
The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many
|
||||
other types into a string. The variable ``i`` is implicitly declared by the
|
||||
``for`` loop and has the type ``int``, because that is what `countup
|
||||
<system.html#countup>`_ returns. ``i`` runs through the values 1, 2, .., 10.
|
||||
Each value is ``echo``-ed. This code does the same:
|
||||
|
||||
.. code-block:: nimrod
|
||||
echo("Counting to 10: ")
|
||||
@@ -400,8 +403,8 @@ Counting down can be achieved as easily (but is less often needed):
|
||||
echo($i)
|
||||
# --> 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
|
||||
that does the same:
|
||||
Since counting up occurs so often in programs, Nimrod also has a `..
|
||||
<system.html#...i,S,T>`_ iterator that does the same:
|
||||
|
||||
.. code-block:: nimrod
|
||||
for i in 1..10:
|
||||
@@ -553,9 +556,10 @@ an expression is allowed:
|
||||
Procedures
|
||||
==========
|
||||
|
||||
To define new commands like ``echo``, ``readline`` in the examples, the concept
|
||||
of a `procedure` is needed. (Some languages call them *methods* or
|
||||
*functions*.) In Nimrod new procedures are defined with the ``proc`` keyword:
|
||||
To define new commands like `echo <system.html#echo>`_ and `readLine
|
||||
<system.html#readLine,TFile>`_ in the examples, the concept of a `procedure`
|
||||
is needed. (Some languages call them *methods* or *functions*.) In Nimrod new
|
||||
procedures are defined with the ``proc`` keyword:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc yes(question: string): bool =
|
||||
@@ -649,7 +653,7 @@ a tuple as a return value instead of using var parameters.
|
||||
Discard statement
|
||||
-----------------
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -665,8 +669,8 @@ been declared with the ``discardable`` pragma:
|
||||
|
||||
p(3, 4) # now valid
|
||||
|
||||
The discard statement can also be used to create block comments as described
|
||||
in the `Comments`_.
|
||||
The ``discard`` statement can also be used to create block comments as
|
||||
described in the `Comments`_ section.
|
||||
|
||||
|
||||
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(true)) # calls the toString(x: bool) proc
|
||||
|
||||
(Note that ``toString`` is usually the ``$`` operator in Nimrod.)
|
||||
The compiler chooses the most appropriate proc for the ``toString`` calls. How
|
||||
this overloading resolution algorithm works exactly is not discussed here
|
||||
(it will be specified in the manual soon).
|
||||
However, it does not lead to nasty surprises and is based on a quite simple
|
||||
unification algorithm. Ambiguous calls are reported as errors.
|
||||
(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
|
||||
Nimrod.) The compiler chooses the most appropriate proc for the ``toString``
|
||||
calls. How this overloading resolution algorithm works exactly is not
|
||||
discussed here (it will be specified in the manual soon). However, it does
|
||||
not lead to nasty surprises and is based on a quite simple unification
|
||||
algorithm. Ambiguous calls are reported as errors.
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
proc `$` (x: myDataType): string = ...
|
||||
@@ -811,7 +815,8 @@ Let's return to the boring counting example:
|
||||
for i in countup(1, 10):
|
||||
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
|
||||
proc countup(a, b: int): int =
|
||||
@@ -976,24 +981,25 @@ type:
|
||||
The common operators ``+ - * / < <= == != > >=`` are defined for
|
||||
floats and follow the IEEE standard.
|
||||
|
||||
Automatic type conversion in expressions with different kinds
|
||||
of floating point types is performed: the smaller type is
|
||||
converted to the larger. Integer types are **not** converted to floating point
|
||||
types automatically and vice versa. The ``toInt`` and ``toFloat`` procs can be
|
||||
used for these conversions.
|
||||
Automatic type conversion in expressions with different kinds of floating
|
||||
point types is performed: the smaller type is converted to the larger. Integer
|
||||
types are **not** converted to floating point types automatically and vice
|
||||
versa. The `toInt <system.html#toInt>`_ and `toFloat <system.html#toFloat>`_
|
||||
procs can be used for these conversions.
|
||||
|
||||
|
||||
Internal type representation
|
||||
============================
|
||||
|
||||
As mentioned earlier, the built-in ``$`` (stringify) operator turns any basic
|
||||
type into a string, which you can then print to the screen with the ``echo``
|
||||
proc. However, advanced types, or types you may define yourself won't work with
|
||||
the ``$`` operator until you define one for them. Sometimes you just want to
|
||||
debug the current value of a complex type without having to write its ``$``
|
||||
operator. You can use then the ``repr`` proc which works with any type and
|
||||
even complex data graphs with cycles. The following example shows that even for
|
||||
basic types there is a difference between the ``$`` and ``repr`` outputs:
|
||||
As mentioned earlier, the built-in `$ <system.html#$>`_ (stringify) operator
|
||||
turns any basic type into a string, which you can then print to the screen
|
||||
with the ``echo`` proc. However, advanced types, or types you may define
|
||||
yourself won't work with the ``$`` operator until you define one for them.
|
||||
Sometimes you just want to debug the current value of a complex type without
|
||||
having to write its ``$`` operator. You can use then the `repr
|
||||
<system.html#repr>`_ proc which works with any type and even complex data
|
||||
graphs with cycles. The following example shows that even for basic types
|
||||
there is a difference between the ``$`` and ``repr`` outputs:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var
|
||||
@@ -1087,9 +1093,10 @@ Operation Comment
|
||||
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
||||
----------------- --------------------------------------------------------
|
||||
|
||||
The ``inc dec succ pred`` operations can fail by raising an `EOutOfRange` or
|
||||
`EOverflow` exception. (If the code has been compiled with the proper runtime
|
||||
checks turned on.)
|
||||
The `inc <system.html#inc>`_, `dec <system.html#dec>`_, `succ
|
||||
<system.html#succ>`_ and `pred <system.html#pred>`_ operations can fail by
|
||||
raising an `EOutOfRange` or `EOverflow` exception. (If the code has been
|
||||
compiled with the proper runtime checks turned on.)
|
||||
|
||||
|
||||
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
|
||||
subrange types (and vice versa) are allowed.
|
||||
|
||||
The ``system`` module defines the important ``natural`` type as
|
||||
``range[0..high(int)]`` (``high`` returns the maximal value). Other programming
|
||||
languages mandate the usage of unsigned integers for natural numbers. This is
|
||||
often **wrong**: you don't want unsigned arithmetic (which wraps around) just
|
||||
because the numbers cannot be negative. Nimrod's ``natural`` type helps to
|
||||
avoid this common programming error.
|
||||
The ``system`` module defines the important `Natural <system.html#Natural>`_
|
||||
type as ``range[0..high(int)]`` (`high <system.html#high>`_ returns the
|
||||
maximal value). Other programming languages mandate the usage of unsigned
|
||||
integers for natural numbers. This is often **wrong**: you don't want unsigned
|
||||
arithmetic (which wraps around) just because the numbers cannot be negative.
|
||||
Nimrod's ``Natural`` type helps to avoid this common programming error.
|
||||
|
||||
|
||||
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
|
||||
------
|
||||
@@ -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
|
||||
copies the whole array contents.
|
||||
|
||||
The built-in ``len`` proc returns the array's length. ``low(a)`` returns the
|
||||
lowest valid index for the array `a` and ``high(a)`` the highest valid index.
|
||||
The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's
|
||||
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
|
||||
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
|
||||
allocated on the heap and garbage collected.
|
||||
|
||||
Sequences are always indexed with an ``int`` starting at position 0.
|
||||
The ``len``, ``low`` and ``high`` operations are available for sequences too.
|
||||
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
||||
Sequences are always indexed with an ``int`` starting at position 0. The `len
|
||||
<system.html#len,seq[T]>`_, `low <system.html#low>`_ and `high
|
||||
<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
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
from the ``items()`` iterator from the `system <system.html>`_ module. But if
|
||||
you use the two variable form, the first variable will hold the index position
|
||||
and the second variable will hold the value. Here the ``for`` statement is
|
||||
looping over the results from the ``pairs()`` iterator from the `system
|
||||
from the `items() <system.html#items.i,seq[T]>`_ iterator from the `system
|
||||
<system.html>`_ module. But if you use the two variable form, the first
|
||||
variable will hold the index position and the second variable will hold the
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -1308,12 +1279,13 @@ Open arrays
|
||||
-----------
|
||||
**Note**: Openarrays can only be used for parameters.
|
||||
|
||||
Often fixed size arrays turn out to be too inflexible; procedures should
|
||||
be able to deal with arrays of different sizes. The `openarray`:idx: type
|
||||
allows this. Openarrays are always indexed with an ``int`` starting at
|
||||
position 0. The ``len``, ``low`` and ``high`` operations are available
|
||||
for open arrays too. Any array with a compatible base type can be passed to
|
||||
an openarray parameter, the index type does not matter.
|
||||
Often fixed size arrays turn out to be too inflexible; procedures should be
|
||||
able to deal with arrays of different sizes. The `openarray`:idx: type allows
|
||||
this. Openarrays are always indexed with an ``int`` starting at position 0.
|
||||
The `len <system.html#len,TOpenArray>`_, `low <system.html#low>`_ and `high
|
||||
<system.html#high>`_ operations are available for open arrays too. Any array
|
||||
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
|
||||
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:
|
||||
myWriteln(stdout, [$123, $"def", $4.0])
|
||||
|
||||
In this example ``$`` is applied to any argument that is passed to the
|
||||
parameter ``a``. Note that ``$`` applied to strings is a nop.
|
||||
In this example `$ <system.html#$>`_ is applied to any argument that is passed
|
||||
to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
|
||||
nop.
|
||||
|
||||
|
||||
Slices
|
||||
@@ -1431,11 +1404,12 @@ having the same field types.
|
||||
|
||||
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
|
||||
variables. An example of this is the ``splitFile`` proc from the `os module
|
||||
<os.html>`_ which returns the directory, name and extension of a path at the
|
||||
same time. For tuple unpacking to work you have to use parenthesis around the
|
||||
values you want to assign the unpacking to, otherwise you will be assigning the
|
||||
same value to all the individual variables! Example:
|
||||
variables. An example of this is the `splitFile <os.html#splitFile>`_ proc
|
||||
from the `os module <os.html>`_ which returns the directory, name and
|
||||
extension of a path at the same time. For tuple unpacking to work you have to
|
||||
use parenthesis around the values you want to assign the unpacking to,
|
||||
otherwise you will be assigning the same value to all the individual
|
||||
variables! Example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
|
||||
63
doc/tut2.txt
63
doc/tut2.txt
@@ -23,11 +23,13 @@ features.**
|
||||
|
||||
Pragmas
|
||||
=======
|
||||
|
||||
Pragmas are Nimrod's method to give the compiler additional information/
|
||||
commands without introducing a massive number of new keywords. Pragmas are
|
||||
enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial
|
||||
does not cover pragmas. See the `manual <manual.html>`_
|
||||
or `user guide <nimrodc.html>`_ for a description of the available pragmas.
|
||||
commands without introducing a massive number of new keywords. Pragmas are
|
||||
enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial
|
||||
does not cover pragmas. See the `manual <manual.html#pragmas>`_ or `user guide
|
||||
<nimrodc.html#additional-features>`_ for a description of the available
|
||||
pragmas.
|
||||
|
||||
|
||||
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).
|
||||
|
||||
If you need to *access* the actual exception object or message inside an
|
||||
``except`` branch you can use the getCurrentException() and
|
||||
getCurrentExceptionMsg() procs from the `system <system.html>`_ module.
|
||||
Example:
|
||||
``except`` branch you can use the `getCurrentException()
|
||||
<system.html#getCurrentException>`_ and `getCurrentExceptionMsg()
|
||||
<system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_
|
||||
module. Example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
try:
|
||||
@@ -435,48 +438,6 @@ Example:
|
||||
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
|
||||
---------------------------------------
|
||||
|
||||
@@ -663,8 +624,8 @@ statement:
|
||||
declareInNewScope(b, int)
|
||||
b = 42 # does not work, `b` is unknown
|
||||
|
||||
(The manual explains why the ``immediate`` pragma is needed for these
|
||||
templates.)
|
||||
(The `manual explains <manual.html#ordinary-vs-immediate-templates>`_ why the
|
||||
``immediate`` pragma is needed for these templates.)
|
||||
|
||||
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
|
||||
|
||||
@@ -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 */; };
|
||||
D531424E15BC87B6005EFF20 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424B15BC87B6005EFF20 /* main.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 */; };
|
||||
/* 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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -135,7 +135,7 @@
|
||||
D592E19015C7120F005258EA /* backend.h */,
|
||||
D531426F15BC94B1005EFF20 /* backend.m */,
|
||||
D592E19115C71415005258EA /* nimbase.h */,
|
||||
D531427115BC94B1005EFF20 /* system.m */,
|
||||
D531427115BC94B1005EFF20 /* stdlib_system.m */,
|
||||
);
|
||||
name = nimrod;
|
||||
sourceTree = "<group>";
|
||||
@@ -229,7 +229,7 @@
|
||||
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */,
|
||||
D531424E15BC87B6005EFF20 /* main.m in Sources */,
|
||||
D531427215BC94B1005EFF20 /* backend.m in Sources */,
|
||||
D531427415BC94B1005EFF20 /* system.m in Sources */,
|
||||
D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */,
|
||||
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -259,11 +259,7 @@
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 3.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"-weak_library",
|
||||
/usr/lib/libSystem.B.dylib,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -284,12 +280,8 @@
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 3.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
||||
OTHER_LDFLAGS = (
|
||||
"-weak_library",
|
||||
/usr/lib/libSystem.B.dylib,
|
||||
);
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
||||
@@ -22,7 +22,7 @@ DEST_NIMBASE=build/nimcache/nimbase.h
|
||||
if [ -d src ]
|
||||
then
|
||||
$PATH_TO_NIMROD objc --noMain --app:lib \
|
||||
--nimcache:build/nimcache --compileOnly \
|
||||
--nimcache:./build/nimcache --compileOnly \
|
||||
--header --cpu:i386 ../nimrod_backend/backend.nim
|
||||
if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
|
||||
then
|
||||
|
||||
@@ -58,8 +58,6 @@ Currently, the following C compilers are supported under Windows:
|
||||
| http://www.mingw.org/download.shtml
|
||||
- | LLVM with Clang or GNU C/C++ frontend
|
||||
| http://llvm.org/releases/download.html
|
||||
- | Digital Mars C++
|
||||
| http://www.digitalmars.com/download/freecompiler.html
|
||||
|
||||
However, most testing is done with GCC.
|
||||
|
||||
|
||||
38
koch.nim
38
koch.nim
@@ -43,7 +43,7 @@ Possible Commands:
|
||||
web generates the website
|
||||
csource [options] builds the C sources for installation
|
||||
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
|
||||
update updates nimrod to the latest version from github
|
||||
(compile koch with -d:withUpdate to enable)
|
||||
@@ -77,6 +77,14 @@ proc tryExec(cmd: string): bool =
|
||||
echo(cmd)
|
||||
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
|
||||
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
|
||||
|
||||
@@ -84,21 +92,25 @@ proc csource(args: string) =
|
||||
exec("$4 cc $1 -r $3 --var:version=$2 csource compiler/nimrod.ini $1" %
|
||||
[args, NimrodVersion, compileNimInst, findNim()])
|
||||
|
||||
proc zip(args: string) =
|
||||
exec("$3 cc -r $2 --var:version=$1 zip compiler/nimrod.ini" %
|
||||
proc zip(args: string) =
|
||||
exec("$3 cc -r $2 --var:version=$1 --var:mingw=mingw32 scripts compiler/nimrod.ini" %
|
||||
[NimrodVersion, compileNimInst, findNim()])
|
||||
exec("$# --var:version=$# --var:mingw=mingw32 zip compiler/nimrod.ini" %
|
||||
["tools/niminst/niminst".exe, NimrodVersion])
|
||||
|
||||
proc buildTool(toolname, args: string) =
|
||||
exec("$# cc $# $#" % [findNim(), args, toolname])
|
||||
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
|
||||
|
||||
proc inno(args: string) =
|
||||
# make sure we have generated the c2nim and niminst executables:
|
||||
proc nsis(args: string) =
|
||||
# make sure we have generated the niminst executables:
|
||||
buildTool("tools/niminst/niminst", args)
|
||||
buildTool("tools/nimgrep", args)
|
||||
buildTool("compiler/c2nim/c2nim", args)
|
||||
exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nimrod" %
|
||||
NimrodVersion)
|
||||
# produce 'nimrod_debug.exe':
|
||||
exec "nimrod c compiler" / "nimrod.nim"
|
||||
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) =
|
||||
exec("$# cc -r $# --var:version=$# scripts compiler/nimrod.ini" %
|
||||
@@ -136,16 +148,8 @@ proc findStartNimrod: string =
|
||||
echo("Found no nimrod compiler and every attempt to build one failed!")
|
||||
quit("FAILURE")
|
||||
|
||||
proc safeRemove(filename: string) =
|
||||
if existsFile(filename): removeFile(filename)
|
||||
|
||||
proc thVersion(i: int): string =
|
||||
result = ("compiler" / "nimrod" & $i).exe
|
||||
|
||||
proc copyExe(source, dest: string) =
|
||||
safeRemove(dest)
|
||||
copyFile(dest=dest, source=source)
|
||||
inclFilePermissions(dest, {fpUserExec})
|
||||
|
||||
proc boot(args: string) =
|
||||
var output = "compiler" / "nimrod".exe
|
||||
@@ -303,7 +307,7 @@ of cmdArgument:
|
||||
of "web": web(op.cmdLineRest)
|
||||
of "csource", "csources": csource(op.cmdLineRest)
|
||||
of "zip": zip(op.cmdLineRest)
|
||||
of "inno": inno(op.cmdLineRest)
|
||||
of "nsis": nsis(op.cmdLineRest)
|
||||
of "install": install(op.cmdLineRest)
|
||||
of "test", "tests": tests(op.cmdLineRest)
|
||||
of "update":
|
||||
|
||||
@@ -627,7 +627,7 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
|
||||
case node.kind
|
||||
of nnkIdent:
|
||||
result = $node.ident
|
||||
of nnkStrLit:
|
||||
of nnkStrLit..nnkTripleStrLit:
|
||||
result = node.strVal
|
||||
else:
|
||||
badNodeKind node.kind, "$"
|
||||
|
||||
@@ -102,7 +102,7 @@ proc newAny(value: pointer, rawType: PNimType): TAny =
|
||||
result.value = value
|
||||
result.rawType = rawType
|
||||
|
||||
when defined(system.TVarSlot):
|
||||
when declared(system.TVarSlot):
|
||||
proc toAny*(x: TVarSlot): TAny {.inline.} =
|
||||
## constructs a ``TAny`` object from a variable slot ``x``.
|
||||
## 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)
|
||||
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 =
|
||||
## retrieve the char value out of `x`. `x` needs to represent a char.
|
||||
var t = skipRange(x.rawtype)
|
||||
|
||||
@@ -19,12 +19,13 @@ type
|
||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||
|
||||
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
|
||||
FReadDb* = object of FDB ## effect that denotes a read operation
|
||||
FWriteDb* = object of FDB ## effect that denotes a write operation
|
||||
|
||||
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||
|
||||
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
||||
## used as a raw-string-literal modifier:
|
||||
## ``sql"update user set counter = counter + 1"``
|
||||
@@ -33,14 +34,14 @@ proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||
## on, later versions will check the string for valid syntax.
|
||||
result = TSqlQuery(query)
|
||||
|
||||
proc dbError(db: TDbConn) {.noreturn.} =
|
||||
proc dbError*(db: TDbConn) {.noreturn.} =
|
||||
## raises an EDb exception.
|
||||
var e: ref EDb
|
||||
new(e)
|
||||
e.msg = $PQerrorMessage(db)
|
||||
raise e
|
||||
|
||||
proc dbError*(msg: string) {.noreturn.} =
|
||||
proc dbError*(msg: string) {.noreturn.} =
|
||||
## raises an EDb exception with message `msg`.
|
||||
var e: ref EDb
|
||||
new(e)
|
||||
@@ -61,41 +62,70 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||
if c == '?':
|
||||
add(result, dbQuote(args[a]))
|
||||
inc(a)
|
||||
else:
|
||||
else:
|
||||
add(result, c)
|
||||
|
||||
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
||||
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
||||
## tries to execute the query and returns true if successful, false otherwise.
|
||||
var q = dbFormat(query, args)
|
||||
var res = PQExec(db, q)
|
||||
var arr = allocCStringArray(args)
|
||||
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||
nil, nil, 0)
|
||||
deallocCStringArray(arr)
|
||||
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
||||
PQclear(res)
|
||||
|
||||
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||
tags: [FReadDB, FWriteDb].} =
|
||||
## executes the query and raises EDB if not successful.
|
||||
var q = dbFormat(query, args)
|
||||
var res = PQExec(db, q)
|
||||
var arr = allocCStringArray(args)
|
||||
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||
nil, nil, 0)
|
||||
deallocCStringArray(arr)
|
||||
if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||
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 =
|
||||
newSeq(result, L)
|
||||
for i in 0..L-1: result[i] = ""
|
||||
|
||||
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string]): PPGresult =
|
||||
var q = dbFormat(query, args)
|
||||
result = PQExec(db, q)
|
||||
if PQresultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
||||
|
||||
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string]): PPGresult =
|
||||
var arr = allocCStringArray(args)
|
||||
result = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||
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) =
|
||||
for col in 0..cols-1:
|
||||
setLen(r[col], 0)
|
||||
var x = PQgetvalue(res, line, col)
|
||||
add(r[col], x)
|
||||
|
||||
|
||||
iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||
## executes the query and iterates over the result dataset. This is very
|
||||
@@ -109,6 +139,17 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
||||
yield result
|
||||
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,
|
||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||
## retrieves a single row. If the query doesn't return any rows, this proc
|
||||
@@ -119,40 +160,55 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||
setRow(res, result, 0, L)
|
||||
PQclear(res)
|
||||
|
||||
proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
||||
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,
|
||||
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||
## executes the query and returns the whole result dataset.
|
||||
result = @[]
|
||||
for r in FastRows(db, query, args):
|
||||
result.add(r)
|
||||
|
||||
iterator rows*(db: TDbConn, query: TSqlQuery,
|
||||
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,
|
||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||
## same as `FastRows`, but slower and safe.
|
||||
for r in items(GetAllRows(db, query, args)): yield r
|
||||
|
||||
proc getValue*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||
proc getValue*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||
## executes the query and returns the first column of the first row of the
|
||||
## result dataset. Returns "" if the dataset contains no rows or the database
|
||||
## value is NULL.
|
||||
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
|
||||
result = if isNil(x): "" else: $x
|
||||
|
||||
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
|
||||
## executes the query (typically "INSERT") and returns the
|
||||
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
||||
## ``RETURNING id`` to the query, so it only works if your primary key is
|
||||
## named ``id``.
|
||||
var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
|
||||
var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
|
||||
args), 0, 0)
|
||||
if not isNil(x):
|
||||
result = ParseBiggestInt($x)
|
||||
else:
|
||||
result = -1
|
||||
|
||||
proc insertID*(db: TDbConn, query: TSqlQuery,
|
||||
proc insertID*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||
## executes the query (typically "INSERT") and returns the
|
||||
## generated ID for the row. For Postgre this adds
|
||||
@@ -161,9 +217,9 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
|
||||
result = TryInsertID(db, query, args)
|
||||
if result < 0: dbError(db)
|
||||
|
||||
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||
args: varargs[string, `$`]): int64 {.tags: [
|
||||
FReadDB, FWriteDb].} =
|
||||
FReadDB, FWriteDb].} =
|
||||
## executes the query (typically "UPDATE") and returns the
|
||||
## number of affected rows.
|
||||
var q = dbFormat(query, args)
|
||||
@@ -172,7 +228,7 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||
result = parseBiggestInt($PQcmdTuples(res))
|
||||
PQclear(res)
|
||||
|
||||
proc close*(db: TDbConn) {.tags: [FDb].} =
|
||||
proc close*(db: TDbConn) {.tags: [FDb].} =
|
||||
## closes the database connection.
|
||||
if db != nil: PQfinish(db)
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ template `=~` *(s: string, pattern: TRegex): expr =
|
||||
## echo("syntax error")
|
||||
##
|
||||
bind maxSubPatterns
|
||||
when not definedInScope(matches):
|
||||
when not declaredInScope(matches):
|
||||
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
||||
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`
|
||||
## may contain a path that will be created.
|
||||
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)
|
||||
if zipsrc == nil:
|
||||
#echo("Dest: " & dest)
|
||||
|
||||
@@ -328,7 +328,8 @@ struct TFrame {
|
||||
NCSTRING procname;
|
||||
NI line;
|
||||
NCSTRING filename;
|
||||
NI len;
|
||||
NI16 len;
|
||||
NI16 calldepth;
|
||||
};
|
||||
|
||||
#define nimfr(proc, file) \
|
||||
|
||||
@@ -50,7 +50,7 @@ const
|
||||
"break", "case", "cast", "const", "continue", "converter", "discard",
|
||||
"distinct", "div", "do", "elif", "else", "end", "enum", "except", "export",
|
||||
"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",
|
||||
"ptr", "raise", "ref", "return", "shl", "shr", "static",
|
||||
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user