Merge branch 'devel'

This commit is contained in:
Araq
2014-10-19 20:50:14 +02:00
231 changed files with 15082 additions and 10779 deletions

View File

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

View File

@@ -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

View File

@@ -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)])

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -1,4 +0,0 @@
# Use the modules of the compiler
path: "$nimrod/compiler"

View File

@@ -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
};

View File

@@ -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__

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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);

View File

@@ -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';
}

View File

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

View File

@@ -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)

View File

@@ -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:

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -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)

View File

@@ -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

View File

@@ -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) =

View File

@@ -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:

View File

@@ -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, [])

View File

@@ -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)

View File

@@ -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

View File

@@ -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 =

View File

@@ -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

View File

@@ -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",

View File

@@ -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 =

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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
View 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()

View 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
View 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)

View 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

View File

@@ -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""

View File

@@ -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"):

View File

@@ -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!

View File

@@ -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

View File

@@ -1,4 +0,0 @@
# Use the modules of the compiler
path: "$nimrod/compiler"

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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, ')')

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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) =

View File

@@ -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:

View File

@@ -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:

View File

@@ -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.}) =

View File

@@ -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, "")

View File

@@ -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

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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
View 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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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
=================

View File

@@ -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.

View File

@@ -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...

View 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>`_

View File

@@ -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

View File

@@ -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
-----------

View File

@@ -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>

View File

@@ -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.

View File

@@ -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 }

View File

@@ -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
View 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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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.

View File

@@ -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":

View File

@@ -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, "$"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -328,7 +328,8 @@ struct TFrame {
NCSTRING procname;
NI line;
NCSTRING filename;
NI len;
NI16 len;
NI16 calldepth;
};
#define nimfr(proc, file) \

View 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