floating point checks

This commit is contained in:
Andreas Rumpf 2009-12-14 01:38:05 +01:00
commit 3b7ef2288f
30 changed files with 611 additions and 631 deletions

View file

@ -7,10 +7,10 @@ Advanced commands::
check checks the project for syntax and semantic check checks the project for syntax and semantic
parse parses a single file (for debugging Nimrod) parse parses a single file (for debugging Nimrod)
Advanced options: Advanced options:
-w, --warnings:on|off warnings ON|OFF -w, --warnings:on|off turn all warnings on|off
--warning[X]:on|off specific warning X ON|OFF --warning[X]:on|off turn specific warning X on|off
--hints:on|off hints ON|OFF --hints:on|off turn all hints on|off
--hint[X]:on|off specific hint X ON|OFF --hint[X]:on|off turn specific hint X on|off
--lib:PATH set the system library path --lib:PATH set the system library path
-c, --compileOnly compile only; do not assemble or link -c, --compileOnly compile only; do not assemble or link
--noLinking compile but do not link --noLinking compile but do not link
@ -24,8 +24,8 @@ Advanced options:
-l, --passl:OPTION pass an option to the linker -l, --passl:OPTION pass an option to the linker
--genMapping generate a mapping file containing --genMapping generate a mapping file containing
(Nimrod, mangled) identifier pairs (Nimrod, mangled) identifier pairs
--lineDir:on|off generation of #line directive ON|OFF --lineDir:on|off generation of #line directive on|off
--checkpoints:on|off turn on|off checkpoints; for debugging Nimrod --checkpoints:on|off turn checkpoints on|off; for debugging Nimrod
--skipCfg do not read the general configuration file --skipCfg do not read the general configuration file
--skipProjCfg do not read the project's configuration file --skipProjCfg do not read the project's configuration file
--gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC --gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC

View file

@ -14,18 +14,20 @@ Options:
-d, --define:SYMBOL define a conditional symbol -d, --define:SYMBOL define a conditional symbol
-u, --undef:SYMBOL undefine a conditional symbol -u, --undef:SYMBOL undefine a conditional symbol
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--symbolFiles:on|off use symbol files to speed up compilation (buggy!) --stackTrace:on|off turn stack tracing on|off
--stackTrace:on|off code generation for stack trace ON|OFF --lineTrace:on|off turn line tracing on|off
--lineTrace:on|off code generation for line trace ON|OFF --debugger:on|off turn Embedded Nimrod Debugger on|off
--debugger:on|off turn Embedded Nimrod Debugger ON|OFF -x, --checks:on|off turn all runtime checks on|off
-x, --checks:on|off code generation for all runtime checks ON|OFF --objChecks:on|off turn obj conversion checks on|off
--objChecks:on|off code generation for obj conversion checks ON|OFF --fieldChecks:on|off turn case variant field checks on|off
--fieldChecks:on|off code generation for case variant fields ON|OFF --rangeChecks:on|off turn range checks on|off
--rangeChecks:on|off code generation for range checks ON|OFF --boundChecks:on|off turn bound checks on|off
--boundChecks:on|off code generation for bound checks ON|OFF --overflowChecks:on|off turn int over-/underflow checks on|off
--overflowChecks:on|off code generation for over-/underflow checks ON|OFF -a, --assertions:on|off turn assertions on|off
-a, --assertions:on|off code generation for assertions ON|OFF --floatChecks:on|off turn all floating point (NaN/Inf) checks on|off
--deadCodeElim:on|off whole program dead code elimination ON|OFF --nanChecks:on|off turn NaN checks on|off
--infChecks:on|off turn Inf checks on|off
--deadCodeElim:on|off whole program dead code elimination on|off
--opt:none|speed|size optimize not at all or for speed|size --opt:none|speed|size optimize not at all or for speed|size
--app:console|gui|lib generate a console|GUI application|dynamic library --app:console|gui|lib generate a console|GUI application|dynamic library
-r, --run run the compiled program with given arguments -r, --run run the compiled program with given arguments

View file

@ -47,7 +47,7 @@ components called `locations`:idx:. A variable is basically a name for a
location. Each variable and location is of a certain `type`:idx:. The location. Each variable and location is of a certain `type`:idx:. The
variable's type is called `static type`:idx:, the location's type is called variable's type is called `static type`:idx:, the location's type is called
`dynamic type`:idx:. If the static type is not the same as the dynamic type, `dynamic type`:idx:. If the static type is not the same as the dynamic type,
it is a supertype or subtype of the dynamic type. it is a super-type or subtype of the dynamic type.
An `identifier`:idx: is a symbol declared as a name for a variable, type, An `identifier`:idx: is a symbol declared as a name for a variable, type,
procedure, etc. The region of the program over which a declaration applies is procedure, etc. The region of the program over which a declaration applies is
@ -424,8 +424,8 @@ Integers, bool, characters and enumeration types (and subrange of these
types) belong to ordinal types. types) belong to ordinal types.
Pre-defined numerical types Pre-defined integer types
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
These integer types are pre-defined: These integer types are pre-defined:
``int`` ``int``
@ -469,6 +469,14 @@ operation meaning
``int32`` type) ``int32`` type)
====================== ====================================================== ====================== ======================================================
`Automatic type conversion`:idx: is performed in expressions where different
kinds of integer types are used: the smaller type is converted to the larger.
For further details, see `Convertible relation`_.
Pre-defined floating point types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following floating point types are pre-defined: The following floating point types are pre-defined:
``float`` ``float``
@ -482,16 +490,49 @@ floatXX
implementation supports ``float32`` and ``float64``. Literals of these types implementation supports ``float32`` and ``float64``. Literals of these types
have the suffix 'fXX. have the suffix 'fXX.
`Automatic type conversion`:idx: is performed in expressions where different
kinds of integer types are used. However, if the type conversion
loses information, the `EOutOfRange`:idx: exception is raised (if the error
cannot be detected at compile time).
Automatic type conversion in expressions with different kinds Automatic type conversion in expressions with different kinds
of floating point types is performed: the smaller type is of floating point types is performed: See `Convertible relation`_ for further
converted to the larger. Arithmetic performed on floating point types details. Arithmetic performed on floating point types follows the IEEE
follows the IEEE standard. Integer types are not converted to floating point standard. Integer types are not converted to floating point types automatically
types automatically and vice versa. and vice versa.
The IEEE standard defines five types of floating-point exceptions:
* Invalid: operations with mathematically invalid operands,
for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
* Division by zero: divisor is zero and dividend is a finite nonzero number,
for example 1.0/0.0.
* Overflow: operation produces a result that exceeds the range of the exponent,
for example MAXDOUBLE+0.0000000000001e308.
* Underflow: operation produces a result that is too small to be represented
as a normal number, for example, MINDOUBLE * MINDOUBLE.
* Inexact: operation produces a result that cannot be represented with infinite
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
The IEEE exceptions are either ignored at runtime or mapped to the
Nimrod exceptions: `EFloatInvalidOp`:idx, `EFloatDivByZero`:idx:,
`EFloatOverflow`:idx:, `EFloatUnderflow`:idx:, and `EFloatInexact`:idx:\.
These exceptions inherit from the `EFloatingPoint`:idx: base class.
Nimrod provides the pragmas `NaNChecks`:idx and `InfChecks`:idx:\ to control
whether the IEEE exceptions are ignored or trap a Nimrod exception:
.. code-block:: nimrod
{.NanChecks: on, InfChecks: on.}
var a = 1.0
var b = 0.0
echo b / b # raises EFloatInvalidOp
echo a / b # raises EFloatOverflow
In the current implementation ``EFloatDivByZero`` and ``EFloatInexact`` are
never raised. ``EFloatOverflow`` is raised instead of ``EFloatDivByZero``.
There is also a `floatChecks`:idx: pragma that is a short-cut for the
combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
turned off as default.
The only operations that are affected by the ``floatChecks`` pragma are
the ``+``, ``-``, ``*``, ``/`` operators for floating point types.
Boolean type Boolean type

View file

@ -7,6 +7,10 @@
.. contents:: .. contents::
"Look at you, hacker. A pathetic creature of meat and bone, panting and
sweating as you run through my corridors. How can you challenge a perfect,
immortal machine?"
Introduction Introduction
============ ============
@ -242,7 +246,7 @@ memory, but nothing worse happens.
DeadCodeElim Pragma DeadCodeElim Pragma
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
The `deadCodeElim`:idx: pragma only applies to whole modules: It tells the The `deadCodeElim`:idx: pragma only applies to whole modules: It tells the
compiler to activate (or deactivate) dead code elimination for the module the compiler to activate (or deactivate) dead code elimination for the module the
pragma appers in. pragma appers in.
@ -304,13 +308,13 @@ Optimizing string handling
String assignments are sometimes expensive in Nimrod: They are required to String assignments are sometimes expensive in Nimrod: They are required to
copy the whole string. However, the compiler is often smart enough to not copy copy the whole string. However, the compiler is often smart enough to not copy
strings. Due to the argument passing semantics, strings are never copied when strings. Due to the argument passing semantics, strings are never copied when
passed to subroutines. The compiler does not copy strings that are result from passed to subroutines. The compiler does not copy strings that are a result from
a procedure call, because the called procedure returns a new string anyway. a procedure call, because the callee returns a new string anyway.
Thus it is efficient to do: Thus it is efficient to do:
.. code-block:: Nimrod .. code-block:: Nimrod
var s = procA() # assignment will not copy the string; procA allocates a new var s = procA() # assignment will not copy the string; procA allocates a new
# string anyway # string already
However it is not efficient to do: However it is not efficient to do:

View file

@ -101,7 +101,7 @@ proc mean*(x: openarray[float]): float {.noSideEffect.} =
result = sum(x) / toFloat(len(x)) result = sum(x) / toFloat(len(x))
proc variance*(x: openarray[float]): float {.noSideEffect.} = proc variance*(x: openarray[float]): float {.noSideEffect.} =
## computes the mean of the elements in `x`. ## computes the variance of the elements in `x`.
## If `x` is empty, NaN is returned. ## If `x` is empty, NaN is returned.
result = 0.0 result = 0.0
var m = mean(x) var m = mean(x)

View file

@ -222,10 +222,10 @@ type
EFloatingPoint* = object of ESynch ## base class for floating point exceptions EFloatingPoint* = object of ESynch ## base class for floating point exceptions
EFloatInvalidOp* {.compilerproc.} = EFloatInvalidOp* {.compilerproc.} =
object of EFloatingPoint ## Invalid operation according to IEEE: Raised by object of EFloatingPoint ## Invalid operation according to IEEE: Raised by
## 0.0/0.0, sqrt(-1.0), and log(-37.8) for example. ## 0.0/0.0, for example.
EFloatDivByZero* {.compilerproc.} = EFloatDivByZero* {.compilerproc.} =
object of EFloatingPoint ## Division by zero. Divisor is zero and dividend object of EFloatingPoint ## Division by zero. Divisor is zero and dividend
## is a finite nonzero number ## is a finite nonzero number.
EFloatOverflow* {.compilerproc.} = EFloatOverflow* {.compilerproc.} =
object of EFloatingPoint ## Overflow. Operation produces a result object of EFloatingPoint ## Overflow. Operation produces a result
## that exceeds the range of the exponent ## that exceeds the range of the exponent

View file

@ -314,3 +314,21 @@ when not defined(mulInt):
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
return result return result
raiseOverflow() raiseOverflow()
# We avoid setting the FPU control word here for compatibility with libraries
# written in other languages.
proc raiseFloatInvalidOp {.noinline, noreturn.} =
raise newException(EFloatInvalidOp, "FPU operation caused a NaN result")
proc nanCheck(x: float64) {.compilerProc, inline.} =
if x != x: raiseFloatInvalidOp()
proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} =
if x > 0.0:
raise newException(EFloatOverflow, "FPU operation caused an overflow")
else:
raise newException(EFloatUnderflow, "FPU operations caused an underflow")
proc infCheck(x: float64) {.compilerProc, inline.} =
if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x)

View file

@ -37,16 +37,16 @@
when defined(MACOSX): when defined(MACOSX):
const const
LUA_NAME* = "liblua(5.2|5.1|5.0).dylib" LUA_NAME* = "liblua(|5.2|5.1|5.0).dylib"
LUA_LIB_NAME* = "liblua(5.2|5.1|5.0).dylib" LUA_LIB_NAME* = "liblua(|5.2|5.1|5.0).dylib"
elif defined(UNIX): elif defined(UNIX):
const const
LUA_NAME* = "liblua(5.2|5.1|5.0).so.0" LUA_NAME* = "liblua(|5.2|5.1|5.0).so.(|0)"
LUA_LIB_NAME* = "liblua(5.2|5.1|5.0).so.0" LUA_LIB_NAME* = "liblua(|5.2|5.1|5.0).so.(|0)"
else: else:
const const
LUA_NAME* = "lua(5.2|5.1|5.0).dll" LUA_NAME* = "lua(|5.2|5.1|5.0).dll"
LUA_LIB_NAME* = "lua(5.2|5.1|5.0).dll" LUA_LIB_NAME* = "lua(|5.2|5.1|5.0).dll"
type type
size_t* = int size_t* = int
Psize_t* = ptr size_t Psize_t* = ptr size_t
@ -56,7 +56,8 @@ const
LUA_RELEASE* = "Lua 5.1.1" LUA_RELEASE* = "Lua 5.1.1"
LUA_VERSION_NUM* = 501 LUA_VERSION_NUM* = 501
LUA_COPYRIGHT* = "Copyright (C) 1994-2006 Lua.org, PUC-Rio" LUA_COPYRIGHT* = "Copyright (C) 1994-2006 Lua.org, PUC-Rio"
LUA_AUTHORS* = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" # option for multiple returns in `lua_pcall' and `lua_call' LUA_AUTHORS* = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
# option for multiple returns in `lua_pcall' and `lua_call'
LUA_MULTRET* = - 1 # LUA_MULTRET* = - 1 #
#** pseudo-indices #** pseudo-indices
# #
@ -74,16 +75,15 @@ const # thread status; 0 is OK
type type
Plua_State* = Pointer Plua_State* = Pointer
lua_CFunction* = proc (L: Plua_State): int{.cdecl.} # lua_CFunction* = proc (L: Plua_State): int{.cdecl.}
#
#** functions that read/write blocks when loading/dumping Lua chunks #** functions that read/write blocks when loading/dumping Lua chunks
# #
type type
lua_Reader* = proc (L: Plua_State, ud: Pointer, sz: Psize_t): cstring{.cdecl.} lua_Reader* = proc (L: Plua_State, ud: Pointer, sz: Psize_t): cstring{.cdecl.}
lua_Writer* = proc (L: Plua_State, p: Pointer, sz: size_t, ud: Pointer): int{. lua_Writer* = proc (L: Plua_State, p: Pointer, sz: size_t, ud: Pointer): int{.
cdecl.} # cdecl.}
#** prototype for memory-allocation functions
#
lua_Alloc* = proc (ud, theptr: Pointer, osize, nsize: size_t){.cdecl.} lua_Alloc* = proc (ud, theptr: Pointer, osize, nsize: size_t){.cdecl.}
const const
@ -218,6 +218,7 @@ proc lua_getallocf*(L: Plua_State, ud: ptr Pointer): lua_Alloc{.cdecl,
dynlib: LUA_NAME, importc.} dynlib: LUA_NAME, importc.}
proc lua_setallocf*(L: Plua_State, f: lua_Alloc, ud: Pointer){.cdecl, proc lua_setallocf*(L: Plua_State, f: lua_Alloc, ud: Pointer){.cdecl,
dynlib: LUA_NAME, importc.} dynlib: LUA_NAME, importc.}
# #
#** Garbage-collection functions and options #** Garbage-collection functions and options
# #
@ -229,7 +230,9 @@ const
LUA_GCCOUNTB* = 4 LUA_GCCOUNTB* = 4
LUA_GCSTEP* = 5 LUA_GCSTEP* = 5
LUA_GCSETPAUSE* = 6 LUA_GCSETPAUSE* = 6
LUA_GCSETSTEPMUL* = 7 # LUA_GCSETSTEPMUL* = 7
#
#** =============================================================== #** ===============================================================
#** some useful macros #** some useful macros
#** =============================================================== #** ===============================================================
@ -259,7 +262,9 @@ proc lua_getregistry*(L: Plua_State)
proc lua_getgccount*(L: Plua_State): int proc lua_getgccount*(L: Plua_State): int
type type
lua_Chunkreader* = lua_Reader lua_Chunkreader* = lua_Reader
lua_Chunkwriter* = lua_Writer # lua_Chunkwriter* = lua_Writer
#
#** {====================================================================== #** {======================================================================
#** Debug API #** Debug API
#** ======================================================================= #** =======================================================================
@ -297,7 +302,9 @@ type
i_ci*: int # active function i_ci*: int # active function
Plua_Debug* = ptr lua_Debug Plua_Debug* = ptr lua_Debug
lua_Hook* = proc (L: Plua_State, ar: Plua_Debug){.cdecl.} # lua_Hook* = proc (L: Plua_State, ar: Plua_Debug){.cdecl.}
#
#** {====================================================================== #** {======================================================================
#** Debug API #** Debug API
#** ======================================================================= #** =======================================================================

View file

@ -303,10 +303,10 @@ type
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mDivI64, mModI64,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
mAddF64, mSubF64, mMulF64, mDivF64, mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU, mMinF64, mMaxF64, mAddU, mSubU, mMulU,
mDivU, mModU, mAddU64, mSubU64, mMulU64, mDivU64, mModU64, mEqI, mLeI, mLtI, mDivU, mModU, mAddU64, mSubU64, mMulU64, mDivU64, mModU64, mEqI, mLeI, mLtI,
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, mLeU, mLtU, mLeU64, mLtU64, mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, mLeU, mLtU, mLeU64, mLtU64,

View file

@ -118,7 +118,8 @@ proc genRawSetData(cs: TBitSet, size: int): PRope =
frmt = "0x$1}$n" frmt = "0x$1}$n"
appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))]) appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))])
else: else:
result = intLiteral(bitSetToWord(cs, size)) # result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2)) result = intLiteral(bitSetToWord(cs, size))
# result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
proc genSetNode(p: BProc, n: PNode): PRope = proc genSetNode(p: BProc, n: PNode): PRope =
var var
@ -384,14 +385,12 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
"modInt64"] "modInt64"]
opr: array[mAddi..mModi64, string] = ["+", "-", "*", "/", "%", "+", "-", opr: array[mAddi..mModi64, string] = ["+", "-", "*", "/", "%", "+", "-",
"*", "/", "%"] "*", "/", "%"]
var var a, b: TLoc
a, b: TLoc
t: PType
assert(e.sons[1].typ != nil) assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil) assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
t = skipTypes(e.typ, abstractRange) var t = skipTypes(e.typ, abstractRange)
if getSize(t) >= platform.IntSize: if getSize(t) >= platform.IntSize:
if optOverflowCheck in p.options: if optOverflowCheck in p.options:
useMagic(p.module, prc[m]) useMagic(p.module, prc[m])
@ -437,8 +436,12 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const const
binArithTab: array[mShrI..mXor, string] = ["(NI$3)((NU$3)($1) >> (NU$3)($2))", # binArithTab: array[mAddF64..mXor, string] = [
# ShrI "($1 + $2)", # AddF64
"($1 - $2)", # SubF64
"($1 * $2)", # MulF64
"($1 / $2)", # DivF64
"(NI$3)((NU$3)($1) >> (NU$3)($2))", # ShrI
"(NI$3)((NU$3)($1) << (NU$3)($2))", # ShlI "(NI$3)((NU$3)($1) << (NU$3)($2))", # ShlI
"(NI$3)($1 & $2)", # BitandI "(NI$3)($1 & $2)", # BitandI
"(NI$3)($1 | $2)", # BitorI "(NI$3)($1 | $2)", # BitorI
@ -452,10 +455,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"($1 ^ $2)", # BitxorI64 "($1 ^ $2)", # BitxorI64
"(($1 <= $2) ? $1 : $2)", # MinI64 "(($1 <= $2) ? $1 : $2)", # MinI64
"(($1 >= $2) ? $1 : $2)", # MaxI64 "(($1 >= $2) ? $1 : $2)", # MaxI64
"($1 + $2)", # AddF64
"($1 - $2)", # SubF64
"($1 * $2)", # MulF64
"($1 / $2)", # DivF64
"(($1 <= $2) ? $1 : $2)", # MinF64 "(($1 <= $2) ? $1 : $2)", # MinF64
"(($1 >= $2) ? $1 : $2)", # MaxF64 "(($1 >= $2) ? $1 : $2)", # MaxF64
"(NI$3)((NU$3)($1) + (NU$3)($2))", # AddU "(NI$3)((NU$3)($1) + (NU$3)($2))", # AddU
@ -503,7 +502,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
assert(e.sons[1].typ != nil) assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil) assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) # BUGFIX: cannot use result-type here, as it may be a boolean InitLocExpr(p, e.sons[2], b)
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8 s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s)])) ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s)]))
@ -672,14 +672,12 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
genRecordField(p, e.sons[0], d) genRecordField(p, e.sons[0], d)
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) = proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
var var a, b: TLoc
a, b: TLoc
ty: PType
first: PRope
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, e.sons[1], b)
ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs) var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
first = intLiteral(firstOrd(ty)) # emit range check: var first = intLiteral(firstOrd(ty))
# emit range check:
if (optBoundsCheck in p.options): if (optBoundsCheck in p.options):
if not isConstExpr(e.sons[1]): if not isConstExpr(e.sons[1]):
# semantic pass has already checked for const index expressions # semantic pass has already checked for const index expressions
@ -696,12 +694,10 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
ropef("$1[($2)-$3]", [rdLoc(a), rdCharLoc(b), first])) ropef("$1[($2)-$3]", [rdLoc(a), rdCharLoc(b), first]))
proc genCStringElem(p: BProc, e: PNode, d: var TLoc) = proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
var var a, b: TLoc
a, b: TLoc
ty: PType
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, e.sons[1], b)
ty = skipTypes(a.t, abstractVarRange) var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)])) ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)]))
@ -719,12 +715,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)])) ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)]))
proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) = proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) =
var var a, b: TLoc
a, b: TLoc
ty: PType
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, e.sons[1], b)
ty = skipTypes(a.t, abstractVarRange) var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check: ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check:
if (optBoundsCheck in p.options): if (optBoundsCheck in p.options):
@ -770,7 +764,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
getTemp(p, e.typ, tmp) # force it into a temp! getTemp(p, e.typ, tmp) # force it into a temp!
expr(p, e.sons[1], tmp) expr(p, e.sons[1], tmp)
L = getLabel(p) L = getLabel(p)
if m == mOr: # mAnd: if m == mOr:
appf(p.s[cpsStmts], "if ($1) goto $2;$n", [rdLoc(tmp), L]) appf(p.s[cpsStmts], "if ($1) goto $2;$n", [rdLoc(tmp), L])
else: else:
appf(p.s[cpsStmts], "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) appf(p.s[cpsStmts], "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
@ -888,15 +882,12 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# appendChar(tmp0, 'z'); # appendChar(tmp0, 'z');
# asgn(s, tmp0); # asgn(s, tmp0);
# } # }
var var a, tmp: TLoc
a, tmp: TLoc
appends, lens: PRope
L: int
useMagic(p.module, "rawNewString") useMagic(p.module, "rawNewString")
getTemp(p, e.typ, tmp) getTemp(p, e.typ, tmp)
L = 0 var L = 0
appends = nil var appends: PRope = nil
lens = nil var lens: PRope = nil
for i in countup(0, sonsLen(e) - 2): for i in countup(0, sonsLen(e) - 2):
# compute the length expression: # compute the length expression:
initLocExpr(p, e.sons[i + 1], a) initLocExpr(p, e.sons[i + 1], a)
@ -1060,7 +1051,8 @@ proc genNewFinalize(p: BProc, e: PNode) =
oldModule: BModule oldModule: BModule
useMagic(p.module, "newObj") useMagic(p.module, "newObj")
refType = skipTypes(e.sons[1].typ, abstractVarRange) refType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a) # This is a little hack: InitLocExpr(p, e.sons[1], a)
# This is a little hack:
# XXX this is also a bug, if the finalizer expression produces side-effects # XXX this is also a bug, if the finalizer expression produces side-effects
oldModule = p.module oldModule = p.module
p.module = gNimDat p.module = gNimDat
@ -1076,11 +1068,9 @@ proc genNewFinalize(p: BProc, e: PNode) =
genObjectInit(p, bt, a, false) genObjectInit(p, bt, a, false)
proc genRepr(p: BProc, e: PNode, d: var TLoc) = proc genRepr(p: BProc, e: PNode, d: var TLoc) =
var var a: TLoc
a: TLoc
t: PType
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
t = skipTypes(e.sons[1].typ, abstractVarRange) var t = skipTypes(e.sons[1].typ, abstractVarRange)
case t.kind case t.kind
of tyInt..tyInt64: of tyInt..tyInt64:
UseMagic(p.module, "reprInt") UseMagic(p.module, "reprInt")
@ -1108,8 +1098,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyOpenArray: of tyOpenArray:
useMagic(p.module, "reprOpenArray") useMagic(p.module, "reprOpenArray")
case a.t.kind case a.t.kind
of tyOpenArray: of tyOpenArray: putIntoDest(p, d, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
putIntoDest(p, d, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
of tyString, tySequence: of tyString, tySequence:
putIntoDest(p, d, e.typ, ropef("$1->data, $1->Sup.len", [rdLoc(a)])) putIntoDest(p, d, e.typ, ropef("$1->data, $1->Sup.len", [rdLoc(a)]))
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
@ -1137,8 +1126,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, magic, frmt: string) =
genAssignment(p, d, a, {}) genAssignment(p, d, a, {})
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var typ: PType var typ = skipTypes(e.sons[1].Typ, abstractPtrs)
typ = skipTypes(e.sons[1].Typ, abstractPtrs)
case typ.kind case typ.kind
of tyOpenArray: of tyOpenArray:
while e.sons[1].kind == nkPassAsOpenArray: e.sons[1] = e.sons[1].sons[0] while e.sons[1].kind == nkPassAsOpenArray: e.sons[1] = e.sons[1].sons[0]
@ -1157,14 +1145,12 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: InternalError(e.info, "genArrayLen()") else: InternalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
var var a, b: TLoc
a, b: TLoc
t: PType
assert(d.k == locNone) assert(d.k == locNone)
useMagic(p.module, "setLengthSeq") useMagic(p.module, "setLengthSeq")
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
t = skipTypes(e.sons[1].typ, abstractVar) var t = skipTypes(e.sons[1].typ, abstractVar)
appf(p.s[cpsStmts], "$1 = ($3) setLengthSeq(&($1)->Sup, sizeof($4), $2);$n", [ appf(p.s[cpsStmts], "$1 = ($3) setLengthSeq(&($1)->Sup, sizeof($4), $2);$n", [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
getTypeDesc(p.module, t.sons[0])]) getTypeDesc(p.module, t.sons[0])])
@ -1202,8 +1188,7 @@ proc fewCmps(s: PNode): bool =
elif elemType(s.typ).Kind in {tyInt, tyInt16..tyInt64}: elif elemType(s.typ).Kind in {tyInt, tyInt16..tyInt64}:
result = true # better not emit the set if int is basetype! result = true # better not emit the set if int is basetype!
else: else:
result = sonsLen(s) <= result = sonsLen(s) <= 8 # 8 seems to be a good value
8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])) putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]))
@ -1224,16 +1209,14 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var var a, b, x, y: TLoc
a, b, x, y: TLoc
length: int
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]): if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set: # a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons # do not emit the set, but generate a bunch of comparisons
initLocExpr(p, e.sons[2], a) initLocExpr(p, e.sons[2], a)
initLoc(b, locExpr, e.typ, OnUnknown) initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(") b.r = toRope("(")
length = sonsLen(e.sons[1]) var length = sonsLen(e.sons[1])
for i in countup(0, length - 1): for i in countup(0, length - 1):
if e.sons[1].sons[i].Kind == nkRange: if e.sons[1].sons[i].Kind == nkRange:
InitLocExpr(p, e.sons[1].sons[i].sons[0], x) InitLocExpr(p, e.sons[1].sons[i].sons[0], x)
@ -1255,56 +1238,45 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const const
lookupOpr: array[mLeSet..mSymDiffSet, string] = ["for ($1 = 0; $1 < $2; $1++) { $n" & lookupOpr: array[mLeSet..mSymDiffSet, string] = [
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" & "for ($1 = 0; $1 < $2; $1++) { $n" &
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" &
" if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" &
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n" & " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n" &
"if ($3) $3 = (memcmp($4, $5, $2) != 0);$n", "&", "|", "& ~", "^"] "if ($3) $3 = (memcmp($4, $5, $2) != 0);$n",
var "&", "|", "& ~", "^"]
size: int var a, b, i: TLoc
setType: PType var setType = skipTypes(e.sons[1].Typ, abstractVar)
a, b, i: TLoc var size = int(getSize(setType))
ts: string
setType = skipTypes(e.sons[1].Typ, abstractVar)
size = int(getSize(setType))
case size case size
of 1, 2, 4, 8: of 1, 2, 4, 8:
case op case op
of mIncl: of mIncl:
ts = "NI" & $(size * 8) var ts = "NI" & $(size * 8)
binaryStmtInExcl(p, e, d, binaryStmtInExcl(p, e, d,
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n") "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n")
of mExcl: of mExcl:
ts = "NI" & $(size * 8) var ts = "NI" & $(size * 8)
binaryStmtInExcl(p, e, d, "$1 &= ~(1 << ((" & ts & ")($2) % (sizeof(" & binaryStmtInExcl(p, e, d, "$1 &= ~(1 << ((" & ts & ")($2) % (sizeof(" &
ts & ")*8)));$n") ts & ")*8)));$n")
of mCard: of mCard:
if size <= 4: unaryExprChar(p, e, d, "countBits32", "countBits32($1)") if size <= 4: unaryExprChar(p, e, d, "countBits32", "countBits32($1)")
else: unaryExprChar(p, e, d, "countBits64", "countBits64($1)") else: unaryExprChar(p, e, d, "countBits64", "countBits64($1)")
of mLtSet: of mLtSet: binaryExprChar(p, e, d, "", "(($1 & ~ $2 ==0)&&($1 != $2))")
binaryExprChar(p, e, d, "", "(($1 & ~ $2 ==0)&&($1 != $2))") of mLeSet: binaryExprChar(p, e, d, "", "(($1 & ~ $2)==0)")
of mLeSet: of mEqSet: binaryExpr(p, e, d, "", "($1 == $2)")
binaryExprChar(p, e, d, "", "(($1 & ~ $2)==0)") of mMulSet: binaryExpr(p, e, d, "", "($1 & $2)")
of mEqSet: of mPlusSet: binaryExpr(p, e, d, "", "($1 | $2)")
binaryExpr(p, e, d, "", "($1 == $2)") of mMinusSet: binaryExpr(p, e, d, "", "($1 & ~ $2)")
of mMulSet: of mSymDiffSet: binaryExpr(p, e, d, "", "($1 ^ $2)")
binaryExpr(p, e, d, "", "($1 & $2)")
of mPlusSet:
binaryExpr(p, e, d, "", "($1 | $2)")
of mMinusSet:
binaryExpr(p, e, d, "", "($1 & ~ $2)")
of mSymDiffSet:
binaryExpr(p, e, d, "", "($1 ^ $2)")
of mInSet: of mInSet:
genInOp(p, e, d) genInOp(p, e, d)
else: internalError(e.info, "genSetOp()") else: internalError(e.info, "genSetOp()")
else: else:
case op case op
of mIncl: of mIncl: binaryStmtInExcl(p, e, d, "$1[$2/8] |=(1<<($2%8));$n")
binaryStmtInExcl(p, e, d, "$1[$2/8] |=(1<<($2%8));$n") of mExcl: binaryStmtInExcl(p, e, d, "$1[$2/8] &= ~(1<<($2%8));$n")
of mExcl: of mCard: unaryExprChar(p, e, d, "cardSet", "cardSet($1, " & $size & ')')
binaryStmtInExcl(p, e, d, "$1[$2/8] &= ~(1<<($2%8));$n")
of mCard:
unaryExprChar(p, e, d, "cardSet", "cardSet($1, " & $(size) & ')')
of mLtSet, mLeSet: of mLtSet, mLeSet:
getTemp(p, getSysType(tyInt), i) # our counter getTemp(p, getSysType(tyInt), i) # our counter
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
@ -1324,8 +1296,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [ "for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
toRope(lookupOpr[op])]) toRope(lookupOpr[op])])
of mInSet: of mInSet: genInOp(p, e, d)
genInOp(p, e, d)
else: internalError(e.info, "genSetOp") else: internalError(e.info, "genSetOp")
proc genOrd(p: BProc, e: PNode, d: var TLoc) = proc genOrd(p: BProc, e: PNode, d: var TLoc) =
@ -1347,10 +1318,8 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
[getTypeDesc(p.module, e.typ), rdCharLoc(a)])) [getTypeDesc(p.module, e.typ), rdCharLoc(a)]))
proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) = proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
var var a: TLoc
a: TLoc var dest = skipTypes(n.typ, abstractVar)
dest: PType
dest = skipTypes(n.typ, abstractVar)
if not (optRangeCheck in p.options): if not (optRangeCheck in p.options):
InitLocExpr(p, n.sons[0], a) InitLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, ropef("(($1) ($2))", putIntoDest(p, d, n.typ, ropef("(($1) ($2))",
@ -1367,12 +1336,10 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
genCast(p, e, d) genCast(p, e, d)
proc passToOpenArray(p: BProc, n: PNode, d: var TLoc) = proc passToOpenArray(p: BProc, n: PNode, d: var TLoc) =
var var a: TLoc
a: TLoc
dest: PType
while n.sons[0].kind == nkPassAsOpenArray: while n.sons[0].kind == nkPassAsOpenArray:
n.sons[0] = n.sons[0].sons[0] # BUGFIX n.sons[0] = n.sons[0].sons[0] # BUGFIX
dest = skipTypes(n.typ, abstractVar) var dest = skipTypes(n.typ, abstractVar)
case skipTypes(n.sons[0].typ, abstractVar).kind case skipTypes(n.sons[0].typ, abstractVar).kind
of tyOpenArray: of tyOpenArray:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
@ -1398,11 +1365,9 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
ropef("cstrToNimstr($1)", [rdLoc(a)])) ropef("cstrToNimstr($1)", [rdLoc(a)]))
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
var var x: TLoc
a, b: PNode var a = e.sons[1]
x: TLoc var b = e.sons[2]
a = e.sons[1]
b = e.sons[2]
if (a.kind == nkNilLit) or (b.kind == nkNilLit): if (a.kind == nkNilLit) or (b.kind == nkNilLit):
binaryExpr(p, e, d, "", "($1 == $2)") binaryExpr(p, e, d, "", "($1 == $2)")
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
@ -1431,9 +1396,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
expr(p, t.sons[i], arr) expr(p, t.sons[i], arr)
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) = proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
var var newSeq, elem, a, arr: TLoc
newSeq, elem, a, arr: TLoc
L: int
if t.kind == nkBracket: if t.kind == nkBracket:
t.sons[1].typ = t.typ t.sons[1].typ = t.typ
genSeqConstr(p, t.sons[1], d) genSeqConstr(p, t.sons[1], d)
@ -1442,7 +1405,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
if d.k == locNone: if d.k == locNone:
getTemp(p, t.typ, d) getTemp(p, t.typ, d)
# generate call to newSeq before adding the elements per hand: # generate call to newSeq before adding the elements per hand:
L = int(lengthOrd(t.sons[1].typ)) var L = int(lengthOrd(t.sons[1].typ))
initLoc(newSeq, locExpr, t.typ, OnHeap) initLoc(newSeq, locExpr, t.typ, OnHeap)
newSeq.r = ropef("($1) newSeq($2, $3)", [getTypeDesc(p.module, t.typ), newSeq.r = ropef("($1) newSeq($2, $3)", [getTypeDesc(p.module, t.typ),
genTypeInfo(p.module, t.typ), intLiteral(L)]) genTypeInfo(p.module, t.typ), intLiteral(L)])
@ -1456,12 +1419,32 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
arr.r = ropef("$1[$2]", [rdLoc(a), intLiteral(i)]) arr.r = ropef("$1[$2]", [rdLoc(a), intLiteral(i)])
genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if {optNanCheck, optInfCheck} * p.options != {}:
const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"]
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropef("($2 $1 $3)", [
toRope(opr[m]), rdLoc(a), rdLoc(b)]))
if optNanCheck in p.options:
useMagic(p.module, "nanCheck")
appf(p.s[cpsStmts], "nanCheck($1);$n", [rdLoc(d)])
if optInfCheck in p.options:
useMagic(p.module, "infCheck")
appf(p.s[cpsStmts], "infCheck($1);$n", [rdLoc(d)])
else:
binaryArith(p, e, d, m)
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var line, filen: PRope var line, filen: PRope
case op case op
of mOr, mAnd: genAndOr(p, e, d, op) of mOr, mAnd: genAndOr(p, e, d, op)
of mNot..mToBiggestInt: unaryArith(p, e, d, op) of mNot..mToBiggestInt: unaryArith(p, e, d, op)
of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op) of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op)
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
of mShrI..mXor: binaryArith(p, e, d, op) of mShrI..mXor: binaryArith(p, e, d, op)
of mAddi..mModi64: binaryArithOverflow(p, e, d, op) of mAddi..mModi64: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d) of mRepr: genRepr(p, e, d)

View file

@ -327,7 +327,7 @@ proc libCandidates(s: string, dest: var TStringSeq) =
if le >= 0 and ri > le: if le >= 0 and ri > le:
var prefix = copy(s, 0, le - 1) var prefix = copy(s, 0, le - 1)
var suffix = copy(s, ri + 1) var suffix = copy(s, ri + 1)
for middle in split(copy(s, le + 1, ri - 1), {'|'}): for middle in split(copy(s, le + 1, ri - 1), '|'):
libCandidates(prefix & middle & suffix, dest) libCandidates(prefix & middle & suffix, dest)
else: else:
add(dest, s) add(dest, s)

View file

@ -47,18 +47,20 @@ Options:
-d, --define:SYMBOL define a conditional symbol -d, --define:SYMBOL define a conditional symbol
-u, --undef:SYMBOL undefine a conditional symbol -u, --undef:SYMBOL undefine a conditional symbol
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--symbolFiles:on|off use symbol files to speed up compilation (buggy!) --stackTrace:on|off turn stack tracing on|off
--stackTrace:on|off code generation for stack trace ON|OFF --lineTrace:on|off turn line tracing on|off
--lineTrace:on|off code generation for line trace ON|OFF --debugger:on|off turn Embedded Nimrod Debugger on|off
--debugger:on|off turn Embedded Nimrod Debugger ON|OFF -x, --checks:on|off turn all runtime checks on|off
-x, --checks:on|off code generation for all runtime checks ON|OFF --objChecks:on|off turn obj conversion checks on|off
--objChecks:on|off code generation for obj conversion checks ON|OFF --fieldChecks:on|off turn case variant field checks on|off
--fieldChecks:on|off code generation for case variant fields ON|OFF --rangeChecks:on|off turn range checks on|off
--rangeChecks:on|off code generation for range checks ON|OFF --boundChecks:on|off turn bound checks on|off
--boundChecks:on|off code generation for bound checks ON|OFF --overflowChecks:on|off turn int over-/underflow checks on|off
--overflowChecks:on|off code generation for over-/underflow checks ON|OFF -a, --assertions:on|off turn assertions on|off
-a, --assertions:on|off code generation for assertions ON|OFF --floatChecks:on|off turn all floating point (NaN/Inf) checks on|off
--deadCodeElim:on|off whole program dead code elimination ON|OFF --nanChecks:on|off turn NaN checks on|off
--infChecks:on|off turn Inf checks on|off
--deadCodeElim:on|off whole program dead code elimination on|off
--opt:none|speed|size optimize not at all or for speed|size --opt:none|speed|size optimize not at all or for speed|size
--app:console|gui|lib generate a console|GUI application|dynamic library --app:console|gui|lib generate a console|GUI application|dynamic library
-r, --run run the compiled program with given arguments -r, --run run the compiled program with given arguments
@ -76,10 +78,10 @@ Advanced commands::
check checks the project for syntax and semantic check checks the project for syntax and semantic
parse parses a single file (for debugging Nimrod) parse parses a single file (for debugging Nimrod)
Advanced options: Advanced options:
-w, --warnings:on|off warnings ON|OFF -w, --warnings:on|off turn all warnings on|off
--warning[X]:on|off specific warning X ON|OFF --warning[X]:on|off turn specific warning X on|off
--hints:on|off hints ON|OFF --hints:on|off turn all hints on|off
--hint[X]:on|off specific hint X ON|OFF --hint[X]:on|off turn specific hint X on|off
--lib:PATH set the system library path --lib:PATH set the system library path
-c, --compileOnly compile only; do not assemble or link -c, --compileOnly compile only; do not assemble or link
--noLinking compile but do not link --noLinking compile but do not link
@ -93,8 +95,8 @@ Advanced options:
-l, --passl:OPTION pass an option to the linker -l, --passl:OPTION pass an option to the linker
--genMapping generate a mapping file containing --genMapping generate a mapping file containing
(Nimrod, mangled) identifier pairs (Nimrod, mangled) identifier pairs
--lineDir:on|off generation of #line directive ON|OFF --lineDir:on|off generation of #line directive on|off
--checkpoints:on|off turn on|off checkpoints; for debugging Nimrod --checkpoints:on|off turn checkpoints on|off; for debugging Nimrod
--skipCfg do not read the general configuration file --skipCfg do not read the general configuration file
--skipProjCfg do not read the project's configuration file --skipProjCfg do not read the project's configuration file
--gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC --gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC
@ -152,9 +154,8 @@ proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
info: TLineInfo) = info: TLineInfo) =
var i: int
cmd = "" cmd = ""
i = 0 var i = 0
if (i < len(switch) + 0) and (switch[i] == '-'): inc(i) if (i < len(switch) + 0) and (switch[i] == '-'): inc(i)
if (i < len(switch) + 0) and (switch[i] == '-'): inc(i) if (i < len(switch) + 0) and (switch[i] == '-'): inc(i)
while i < len(switch) + 0: while i < len(switch) + 0:
@ -188,13 +189,9 @@ proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass, proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
info: TLineInfo) = info: TLineInfo) =
var var id = "" # arg = "X]:on|off"
i, x: int var i = 0
n: TNoteKind var n = hintMin
id: string
id = "" # arg = "X]:on|off"
i = 0
n = hintMin
while (i < len(arg) + 0) and (arg[i] != ']'): while (i < len(arg) + 0) and (arg[i] != ']'):
add(id, arg[i]) add(id, arg[i])
inc(i) inc(i)
@ -203,11 +200,11 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
if (i < len(arg) + 0) and (arg[i] in {':', '='}): inc(i) if (i < len(arg) + 0) and (arg[i] in {':', '='}): inc(i)
else: InvalidCmdLineOption(pass, arg, info) else: InvalidCmdLineOption(pass, arg, info)
if state == wHint: if state == wHint:
x = findStr(msgs.HintsToStr, id) var x = findStr(msgs.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin)) if x >= 0: n = TNoteKind(x + ord(hintMin))
else: InvalidCmdLineOption(pass, arg, info) else: InvalidCmdLineOption(pass, arg, info)
else: else:
x = findStr(msgs.WarningsToStr, id) var x = findStr(msgs.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin)) if x >= 0: n = TNoteKind(x + ord(warnMin))
else: InvalidCmdLineOption(pass, arg, info) else: InvalidCmdLineOption(pass, arg, info)
case whichKeyword(copy(arg, i)) case whichKeyword(copy(arg, i))
@ -297,6 +294,10 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
if optProfiler in gOptions: DefineSymbol("profiler") if optProfiler in gOptions: DefineSymbol("profiler")
else: UndefSymbol("profiler") else: UndefSymbol("profiler")
of wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info) of wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info)
of wFloatChecks:
ProcessOnOffSwitch({optNanCheck, optInfCheck}, arg, pass, info)
of wInfChecks: ProcessOnOffSwitch({optInfCheck}, arg, pass, info)
of wNanChecks: ProcessOnOffSwitch({optNanCheck}, arg, pass, info)
of wObjChecks: ProcessOnOffSwitch({optObjCheck}, arg, pass, info) of wObjChecks: ProcessOnOffSwitch({optObjCheck}, arg, pass, info)
of wFieldChecks: ProcessOnOffSwitch({optFieldCheck}, arg, pass, info) of wFieldChecks: ProcessOnOffSwitch({optFieldCheck}, arg, pass, info)
of wRangeChecks: ProcessOnOffSwitch({optRangeCheck}, arg, pass, info) of wRangeChecks: ProcessOnOffSwitch({optRangeCheck}, arg, pass, info)

View file

@ -70,6 +70,7 @@ proc countDefinedSymbols(): int =
proc InitDefines() = proc InitDefines() =
initStrTable(gSymbols) initStrTable(gSymbols)
DefineSymbol("nimrod") # 'nimrod' is always defined DefineSymbol("nimrod") # 'nimrod' is always defined
# add platform specific symbols: # add platform specific symbols:
case targetCPU case targetCPU
of cpuI386: DefineSymbol("x86") of cpuI386: DefineSymbol("x86")
@ -103,7 +104,7 @@ proc InitDefines() =
DefineSymbol("posix") DefineSymbol("posix")
else: else:
nil nil
DefineSymbol("cpu" & $(cpu[targetCPU].bit)) DefineSymbol("cpu" & $cpu[targetCPU].bit)
DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian])) DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian]))
DefineSymbol(cpu[targetCPU].name) DefineSymbol(cpu[targetCPU].name)
DefineSymbol(platform.os[targetOS].name) DefineSymbol(platform.os[targetOS].name)

View file

@ -536,7 +536,7 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
result = ropef("$n$n$1.. index::$n$2", [ind, result]) result = ropef("$n$n$1.. index::$n$2", [ind, result])
of rnContents: of rnContents:
result = ropef("$n$n$1.. contents::", [ind]) result = ropef("$n$n$1.. contents::", [ind])
else: rawMessage(errCannotRenderX, rstnodeKindToStr[n.kind]) else: rawMessage(errCannotRenderX, $n.kind)
proc renderTocEntry(d: PDoc, e: TTocEntry): PRope = proc renderTocEntry(d: PDoc, e: TTocEntry): PRope =
result = dispF("<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>$n", result = dispF("<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>$n",
@ -582,16 +582,12 @@ proc renderImage(d: PDoc, n: PRstNode): PRope =
if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2])) if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2]))
proc renderCodeBlock(d: PDoc, n: PRstNode): PRope = proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
var
m: PRstNode
g: TGeneralTokenizer
langstr: string
lang: TSourceLanguage
result = nil result = nil
if n.sons[2] == nil: return if n.sons[2] == nil: return
m = n.sons[2].sons[0] var m = n.sons[2].sons[0]
if (m.kind != rnLeaf): InternalError("renderCodeBlock") if (m.kind != rnLeaf): InternalError("renderCodeBlock")
langstr = strip(getArgument(n)) var langstr = strip(getArgument(n))
var lang: TSourceLanguage
if langstr == "": if langstr == "":
lang = langNimrod # default language lang = langNimrod # default language
else: else:
@ -600,12 +596,12 @@ proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
rawMessage(warnLanguageXNotSupported, langstr) rawMessage(warnLanguageXNotSupported, langstr)
result = toRope(m.text) result = toRope(m.text)
else: else:
var g: TGeneralTokenizer
initGeneralTokenizer(g, m.text) initGeneralTokenizer(g, m.text)
while true: while true:
getNextToken(g, lang) getNextToken(g, lang)
case g.kind case g.kind
of gtEof: of gtEof: break
break
of gtNone, gtWhitespace: of gtNone, gtWhitespace:
app(result, copy(m.text, g.start + 0, g.length + g.start - 1 + 0)) app(result, copy(m.text, g.start + 0, g.length + g.start - 1 + 0))
else: else:

View file

@ -87,8 +87,7 @@ const
tySet, tyVar, tyRef, tyPtr} tySet, tyVar, tyRef, tyPtr}
proc mapType(typ: PType): TEcmasTypeKind = proc mapType(typ: PType): TEcmasTypeKind =
var t: PType var t = skipTypes(typ, abstractInst)
t = skipTypes(typ, abstractInst)
case t.kind case t.kind
of tyVar, tyRef, tyPtr: of tyVar, tyRef, tyPtr:
if skipTypes(t.sons[0], abstractInst).kind in mappedToObject: if skipTypes(t.sons[0], abstractInst).kind in mappedToObject:
@ -98,29 +97,20 @@ proc mapType(typ: PType): TEcmasTypeKind =
of tyPointer: of tyPointer:
# treat a tyPointer like a typed pointer to an array of bytes # treat a tyPointer like a typed pointer to an array of bytes
result = etyInt result = etyInt
of tyRange, tyDistinct, tyOrdinal: of tyRange, tyDistinct, tyOrdinal: result = mapType(t.sons[0])
result = mapType(t.sons[0]) of tyInt..tyInt64, tyEnum, tyChar: result = etyInt
of tyInt..tyInt64, tyEnum, tyChar: of tyBool: result = etyBool
result = etyInt of tyFloat..tyFloat128: result = etyFloat
of tyBool: of tySet: result = etyObject # map a set to a table
result = etyBool of tyString, tySequence: result = etyInt # little hack to get right semantics
of tyFloat..tyFloat128:
result = etyFloat
of tySet:
result = etyObject # map a set to a table
of tyString, tySequence:
result = etyInt # little hack to get the right semantics
of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray: of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray:
result = etyObject result = etyObject
of tyNil: of tyNil: result = etyNull
result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc: tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc:
result = etyNone result = etyNone
of tyProc: of tyProc: result = etyProc
result = etyProc of tyCString: result = etyString
of tyCString:
result = etyString
proc mangle(name: string): string = proc mangle(name: string): string =
result = "" result = ""
@ -132,7 +122,7 @@ proc mangle(name: string): string =
nil nil
of 'a'..'z', '0'..'9': of 'a'..'z', '0'..'9':
add(result, name[i]) add(result, name[i])
else: result = result & 'X' & toHex(ord(name[i]), 2) else: add(result, 'X' & toHex(ord(name[i]), 2))
proc mangleName(s: PSym): PRope = proc mangleName(s: PSym): PRope =
result = s.loc.r result = s.loc.r
@ -199,8 +189,7 @@ proc genObjectFields(p: var TProc, typ: PType, n: PNode): PRope =
else: internalError(n.info, "genObjectFields") else: internalError(n.info, "genObjectFields")
proc genObjectInfo(p: var TProc, typ: PType, name: PRope) = proc genObjectInfo(p: var TProc, typ: PType, name: PRope) =
var s: PRope var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
"finalizer: null};$n", [name, toRope(ord(typ.kind))]) "finalizer: null};$n", [name, toRope(ord(typ.kind))])
prepend(p.globals.typeInfo, s) prepend(p.globals.typeInfo, s)
appf(p.globals.typeInfo, "var NNI$1 = $2;$n", appf(p.globals.typeInfo, "var NNI$1 = $2;$n",
@ -302,8 +291,8 @@ type
TMagicFrmt = array[0..3, string] TMagicFrmt = array[0..3, string]
const # magic checked op; magic unchecked op; checked op; unchecked op const # magic checked op; magic unchecked op; checked op; unchecked op
ops: array[mAddi..mStrToStr, TMagicFrmt] = [["addInt", "", "addInt($1, $2)", ops: array[mAddi..mStrToStr, TMagicFrmt] = [
"($1 + $2)"], # AddI ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # AddI
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI
["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
@ -313,6 +302,10 @@ const # magic checked op; magic unchecked op; checked op
["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64 ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64 ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64 ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
["", "", "($1 + $2)", "($1 + $2)"], # AddF64
["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI
["", "", "($1 << $2)", "($1 << $2)"], # ShlI ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
["", "", "($1 & $2)", "($1 & $2)"], # BitandI ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
@ -327,10 +320,6 @@ const # magic checked op; magic unchecked op; checked op
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64 ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64 ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64 ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
["", "", "($1 + $2)", "($1 + $2)"], # AddF64
["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64 ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64 ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
["AddU", "AddU", "AddU($1, $2)", "AddU($1, $2)"], # AddU ["AddU", "AddU", "AddU($1, $2)", "AddU($1, $2)"], # AddU
@ -461,8 +450,8 @@ proc genLineDir(p: var TProc, n: PNode, r: var TCompRes) =
appf(r.com, "F.line = $1;$n", [toRope(line)]) appf(r.com, "F.line = $1;$n", [toRope(line)])
proc finishTryStmt(p: var TProc, r: var TCompRes, howMany: int) = proc finishTryStmt(p: var TProc, r: var TCompRes, howMany: int) =
for i in countup(1, howMany): app(r.com, "excHandler = excHandler.prev;" & for i in countup(1, howMany):
tnl) app(r.com, "excHandler = excHandler.prev;" & tnl)
proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) = proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
var var

23
rod/expand_importc.nim Executable file
View file

@ -0,0 +1,23 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Simple tool to expand ``importc`` pragmas. Used for the clean up process of
## the diverse wrappers.
import
os, ropes, idents, ast, pnimsyn, rnimsyn
times, commands, scanner, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt
if paramcount() == 0:
echo ""

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2008 Andreas Rumpf # (c) Copyright 2009 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -37,15 +37,11 @@ proc getModuleFile(n: PNode): string =
result = "" result = ""
proc rawImportSymbol(c: PContext, s: PSym) = proc rawImportSymbol(c: PContext, s: PSym) =
var
check, copy, e: PSym
etyp: PType # enumeration type
it: TIdentIter
# This does not handle stubs, because otherwise loading on demand would be # This does not handle stubs, because otherwise loading on demand would be
# pointless in practice. So importing stubs is fine here! # pointless in practice. So importing stubs is fine here!
copy = s # do not copy symbols when importing! var copy = s # do not copy symbols when importing!
# check if we have already a symbol of the same name: # check if we have already a symbol of the same name:
check = StrTableGet(c.tab.stack[importTablePos], s.name) var check = StrTableGet(c.tab.stack[importTablePos], s.name)
if (check != nil) and (check.id != copy.id): if (check != nil) and (check.id != copy.id):
if not (s.kind in OverloadableSyms): if not (s.kind in OverloadableSyms):
# s and check need to be qualified: # s and check need to be qualified:
@ -53,15 +49,16 @@ proc rawImportSymbol(c: PContext, s: PSym) =
IntSetIncl(c.AmbiguousSymbols, check.id) IntSetIncl(c.AmbiguousSymbols, check.id)
StrTableAdd(c.tab.stack[importTablePos], copy) StrTableAdd(c.tab.stack[importTablePos], copy)
if s.kind == skType: if s.kind == skType:
etyp = s.typ var etyp = s.typ
if etyp.kind in {tyBool, tyEnum}: if etyp.kind in {tyBool, tyEnum}:
for j in countup(0, sonsLen(etyp.n) - 1): for j in countup(0, sonsLen(etyp.n) - 1):
e = etyp.n.sons[j].sym var e = etyp.n.sons[j].sym
if (e.Kind != skEnumField): if (e.Kind != skEnumField):
InternalError(s.info, "rawImportSymbol") InternalError(s.info, "rawImportSymbol")
# BUGFIX: because of aliases for enums the symbol may already # BUGFIX: because of aliases for enums the symbol may already
# have been put into the symbol table # have been put into the symbol table
# BUGFIX: but only iff they are the same symbols! # BUGFIX: but only iff they are the same symbols!
var it: TIdentIter
check = InitIdentIter(it, c.tab.stack[importTablePos], e.name) check = InitIdentIter(it, c.tab.stack[importTablePos], e.name)
while check != nil: while check != nil:
if check.id == e.id: if check.id == e.id:
@ -74,11 +71,8 @@ proc rawImportSymbol(c: PContext, s: PSym) =
addConverter(c, s) # rodgen assures that converters are no stubs addConverter(c, s) # rodgen assures that converters are no stubs
proc importSymbol(c: PContext, ident: PNode, fromMod: PSym) = proc importSymbol(c: PContext, ident: PNode, fromMod: PSym) =
var
s, e: PSym
it: TIdentIter
if (ident.kind != nkIdent): InternalError(ident.info, "importSymbol") if (ident.kind != nkIdent): InternalError(ident.info, "importSymbol")
s = StrTableGet(fromMod.tab, ident.ident) var s = StrTableGet(fromMod.tab, ident.ident)
if s == nil: liMessage(ident.info, errUndeclaredIdentifier, ident.ident.s) if s == nil: liMessage(ident.info, errUndeclaredIdentifier, ident.ident.s)
if s.kind == skStub: loadStub(s) if s.kind == skStub: loadStub(s)
if not (s.Kind in ExportableSymKinds): if not (s.Kind in ExportableSymKinds):
@ -87,7 +81,8 @@ proc importSymbol(c: PContext, ident: PNode, fromMod: PSym) =
case s.Kind case s.Kind
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
# for a overloadable syms add all overloaded routines # for a overloadable syms add all overloaded routines
e = InitIdentIter(it, fromMod.tab, s.name) var it: TIdentIter
var e = InitIdentIter(it, fromMod.tab, s.name)
while e != nil: while e != nil:
if (e.name.id != s.Name.id): InternalError(ident.info, "importSymbol: 3") if (e.name.id != s.Name.id): InternalError(ident.info, "importSymbol: 3")
rawImportSymbol(c, e) rawImportSymbol(c, e)

View file

@ -31,8 +31,7 @@ var compMods: TFileModuleMap = @ []
proc registerModule(filename: string, module: PSym) = proc registerModule(filename: string, module: PSym) =
# all compiled modules # all compiled modules
var length: int var length = len(compMods)
length = len(compMods)
setlen(compMods, length + 1) setlen(compMods, length + 1)
compMods[length].filename = filename compMods[length].filename = filename
compMods[length].module = module compMods[length].module = module
@ -50,6 +49,9 @@ proc newModule(filename: string): PSym =
result.id = - 1 # for better error checking result.id = - 1 # for better error checking
result.kind = skModule result.kind = skModule
result.name = getIdent(splitFile(filename).name) result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
rawMessage(errIdentifierExpected, result.name.s)
result.owner = result # a module belongs to itself result.owner = result # a module belongs to itself
result.info = newLineInfo(filename, 1, 1) result.info = newLineInfo(filename, 1, 1)
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
@ -68,11 +70,8 @@ proc importModule(filename: string): PSym =
liMessage(result.info, errAttemptToRedefine, result.Name.s) liMessage(result.info, errAttemptToRedefine, result.Name.s)
proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym = proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym =
var var rd: PRodReader = nil
rd: PRodReader var f = addFileExt(filename, nimExt)
f: string
rd = nil
f = addFileExt(filename, nimExt)
result = newModule(filename) result = newModule(filename)
if isMainFile: incl(result.flags, sfMainModule) if isMainFile: incl(result.flags, sfMainModule)
if isSystemFile: incl(result.flags, sfSystemModule) if isSystemFile: incl(result.flags, sfSystemModule)

View file

@ -9,3 +9,4 @@
@elif vcc: @elif vcc:
# cgen.speed = "" # cgen.speed = ""
@end @end

View file

@ -17,11 +17,7 @@ var
cmdLineInfo: TLineInfo cmdLineInfo: TLineInfo
proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) = proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
var var p = parseopt.init()
p: TOptParser
bracketLe: int
key, val: string
p = parseopt.init()
while true: while true:
parseopt.next(p) parseopt.next(p)
case p.kind case p.kind
@ -30,10 +26,10 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
of cmdLongOption, cmdShortOption: of cmdLongOption, cmdShortOption:
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here # we fix this here
bracketLe = strutils.find(p.key, '[') var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0: if bracketLe >= 0:
key = copy(p.key, 0, bracketLe - 1) var key = copy(p.key, 0, bracketLe - 1)
val = copy(p.key, bracketLe + 1) & ':' & p.val var val = copy(p.key, bracketLe + 1) & ':' & p.val
ProcessSwitch(key, val, pass, cmdLineInfo) ProcessSwitch(key, val, pass, cmdLineInfo)
else: else:
ProcessSwitch(p.key, p.val, pass, cmdLineInfo) ProcessSwitch(p.key, p.val, pass, cmdLineInfo)
@ -49,16 +45,13 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
rawMessage(errArgsNeedRunOption) rawMessage(errArgsNeedRunOption)
proc HandleCmdLine() = proc HandleCmdLine() =
var var start = getTime()
command, filename, prog: string
start: TTime
start = getTime()
if paramCount() == 0: if paramCount() == 0:
writeCommandLineUsage() writeCommandLineUsage()
else: else:
# Process command line arguments: # Process command line arguments:
command = "" var command = ""
filename = "" var filename = ""
ProcessCmdLine(passCmd1, command, filename) ProcessCmdLine(passCmd1, command, filename)
if filename != "": options.projectPath = splitFile(filename).dir if filename != "": options.projectPath = splitFile(filename).dir
nimconf.LoadConfig(filename) # load the right config file nimconf.LoadConfig(filename) # load the right config file
@ -74,15 +67,11 @@ proc HandleCmdLine() =
rawMessage(hintSuccessX, [$(gLinesCompiled), $(getTime() - start)]) rawMessage(hintSuccessX, [$(gLinesCompiled), $(getTime() - start)])
if optRun in gGlobalOptions: if optRun in gGlobalOptions:
when defined(unix): when defined(unix):
prog = "./" & quoteIfContainsWhite(changeFileExt(filename, "")) var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))
else: else:
prog = quoteIfContainsWhite(changeFileExt(filename, "")) var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
execExternalProgram(prog & ' ' & arguments) execExternalProgram(prog & ' ' & arguments)
#{@emit
# GC_disableMarkAndSweep();
#}
cmdLineInfo = newLineInfo("command line", - 1, - 1) cmdLineInfo = newLineInfo("command line", - 1, - 1)
condsyms.InitDefines() condsyms.InitDefines()
HandleCmdLine() HandleCmdLine()

View file

@ -14,11 +14,14 @@ type # please make sure we have under 32 options
# (improves code efficiency a lot!) # (improves code efficiency a lot!)
TOption* = enum # **keep binary compatible** TOption* = enum # **keep binary compatible**
optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
optOverflowCheck, optNilCheck, optAssert, optLineDir, optWarns, optHints, optOverflowCheck, optNilCheck,
optNaNCheck, optInfCheck,
optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
optLineTrace, # line tracing support (includes stack tracing) optLineTrace, # line tracing support (includes stack tracing)
optEndb, # embedded debugger optEndb, # embedded debugger
optByRef, # use pass by ref for objects (for interfacing with C) optByRef, # use pass by ref for objects
# (for interfacing with C)
optCheckpoints, # check for checkpoints (used for debugging) optCheckpoints, # check for checkpoints (used for debugging)
optProfiler # profiler turned on optProfiler # profiler turned on
TOptions* = set[TOption] TOptions* = set[TOption]
@ -50,12 +53,7 @@ type # please make sure we have under 32 options
const const
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
optOverflowCheck, optBoundsCheck, optAssert} optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
optionToStr*: array[TOption, string] = ["optNone", "optObjCheck",
"optFieldCheck", "optRangeCheck", "optBoundsCheck", "optOverflowCheck",
"optNilCheck", "optAssert", "optLineDir", "optWarns", "optHints",
"optOptimizeSpeed", "optOptimizeSize", "optStackTrace", "optLineTrace",
"optEmdb", "optByRef", "optCheckpoints", "optProfiler"]
var var
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck, gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,

View file

@ -32,7 +32,8 @@ const
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir,
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated} wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
wInfChecks, wNanChecks}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated} wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
@ -220,6 +221,9 @@ proc processOption(c: PContext, n: PNode) =
of wBoundchecks: OnOff(c, n, {optBoundsCheck}) of wBoundchecks: OnOff(c, n, {optBoundsCheck})
of wOverflowchecks: OnOff(c, n, {optOverflowCheck}) of wOverflowchecks: OnOff(c, n, {optOverflowCheck})
of wNilchecks: OnOff(c, n, {optNilCheck}) of wNilchecks: OnOff(c, n, {optNilCheck})
of wFloatChecks: OnOff(c, n, {optNanCheck, optInfCheck})
of wNaNchecks: OnOff(c, n, {optNanCheck})
of wInfChecks: OnOff(c, n, {optInfCheck})
of wAssertions: OnOff(c, n, {optAssert}) of wAssertions: OnOff(c, n, {optAssert})
of wWarnings: OnOff(c, n, {optWarns}) of wWarnings: OnOff(c, n, {optWarns})
of wHints: OnOff(c, n, {optHints}) of wHints: OnOff(c, n, {optHints})
@ -434,7 +438,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, wCallConv, wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, wCallConv,
wDebugger, wProfiler: wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks:
processOption(c, it) # calling conventions (boring...): processOption(c, it) # calling conventions (boring...):
of firstCallConv..lastCallConv: of firstCallConv..lastCallConv:
assert(sym != nil) assert(sym != nil)

View file

@ -7,7 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module implements a *reStructuredText* parser. A larget # This module implements a *reStructuredText* parser. A large
# subset is provided. # subset is provided.
import import
@ -33,25 +33,17 @@ type
rnFieldName, # consisting of a field name ... rnFieldName, # consisting of a field name ...
rnFieldBody, # ... and a field body rnFieldBody, # ... and a field body
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock, rnLineBlock, # rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
# the rnLineBlock, # the | thingie
# |
# thingie
rnLineBlockItem, # sons of the | thing rnLineBlockItem, # sons of the | thing
rnBlockQuote, # text just indented rnBlockQuote, # text just indented
rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, rnLabel, # rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell,
# used rnLabel, # used for footnotes and other things
# for
# footnotes
# and
# other
# things
rnFootnote, # a footnote rnFootnote, # a footnote
rnCitation, # similar to footnote rnCitation, # similar to footnote
rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive
rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock, rnContainer, # rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock,
# ``container`` rnContainer, # ``container`` directive
# directive
rnIndex, # index directve: rnIndex, # index directve:
# .. index:: # .. index::
# key # key
@ -64,22 +56,8 @@ type
rnInterpretedText, # "`" rnInterpretedText, # "`"
rnInlineLiteral, # "``" rnInlineLiteral, # "``"
rnSubstitutionReferences, # "|" rnSubstitutionReferences, # "|"
rnLeaf # a leaf; the node's text field contains the leaf val rnLeaf # a leaf; the node's text field contains the
# leaf val
const
rstnodekindToStr*: array[TRstNodeKind, string] = ["Inner", "Headline",
"Overline", "Transition", "Paragraph", "BulletList", "BulletItem",
"EnumList", "EnumItem", "DefList", "DefItem", "DefName", "DefBody",
"FieldList", "Field", "FieldName", "FieldBody", "OptionList",
"OptionListItem", "OptionGroup", "Option", "OptionString", "OptionArgument",
"Description", "LiteralBlock", "QuotedLiteralBlock", "LineBlock",
"LineBlockItem", "BlockQuote", "Table", "GridTable", "TableRow",
"TableHeaderCell", "TableDataCell", "Label", "Footnote", "Citation",
"StandaloneHyperlink", "Hyperlink", "Ref", "Directive", "DirArg", "Raw",
"Title", "Contents", "Image", "Figure", "CodeBlock", "Container", "Index",
"SubstitutionDef", "GeneralRole", "Sub", "Sup", "Idx", "Emphasis",
"StrongEmphasis", "InterpretedText", "InlineLiteral",
"SubstitutionReferences", "Leaf"]
type # the syntax tree of RST: type # the syntax tree of RST:
PRSTNode* = ref TRstNode PRSTNode* = ref TRstNode
@ -513,7 +491,6 @@ proc clearIndex(index: PRstNode, filename: string) =
proc setIndexPair(index, key, val: PRstNode) = proc setIndexPair(index, key, val: PRstNode) =
var e, a, b: PRstNode var e, a, b: PRstNode
# writeln(rstnodekindToStr[key.kind], ': ', rstnodekindToStr[val.kind]);
assert(index.kind == rnDefList) assert(index.kind == rnDefList)
assert(key.kind != rnDefName) assert(key.kind != rnDefName)
a = newRstNode(rnDefName) a = newRstNode(rnDefName)
@ -590,7 +567,7 @@ proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
result = false result = false
proc isInlineMarkupStart(p: TRstParser, markup: string): bool = proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
var c, d: Char var d: Char
result = p.tok[p.idx].symbol == markup result = p.tok[p.idx].symbol == markup
if not result: if not result:
return # Rule 1: return # Rule 1:
@ -606,7 +583,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
if p.tok[p.idx - 1].symbol == "\\": if p.tok[p.idx - 1].symbol == "\\":
result = false result = false
else: else:
c = p.tok[p.idx - 1].symbol[0] var c = p.tok[p.idx - 1].symbol[0]
case c case c
of '\'', '\"': d = c of '\'', '\"': d = c
of '(': d = ')' of '(': d = ')'
@ -641,30 +618,19 @@ proc match(p: TRstParser, start: int, expr: string): bool =
# 'T' always true # 'T' always true
# 'E' whitespace, indent or eof # 'E' whitespace, indent or eof
# 'e' tkWord or '#' (for enumeration lists) # 'e' tkWord or '#' (for enumeration lists)
var var i = 0
i, j, last, length: int var j = start
c: char var last = len(expr) + 0 - 1
i = 0
j = start
last = len(expr) + 0 - 1
while i <= last: while i <= last:
case expr[i] case expr[i]
of 'w': of 'w': result = p.tok[j].kind == tkWord
result = p.tok[j].kind == tkWord of ' ': result = p.tok[j].kind == tkWhite
of ' ': of 'i': result = p.tok[j].kind == tkIndent
result = p.tok[j].kind == tkWhite of 'p': result = p.tok[j].kind == tkPunct
of 'i': of 'a': result = p.tok[j].kind == tkAdornment
result = p.tok[j].kind == tkIndent of 'o': result = p.tok[j].kind == tkOther
of 'p': of 'T': result = true
result = p.tok[j].kind == tkPunct of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
of 'a':
result = p.tok[j].kind == tkAdornment
of 'o':
result = p.tok[j].kind == tkOther
of 'T':
result = true
of 'E':
result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
of 'e': of 'e':
result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#") result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
if result: if result:
@ -674,8 +640,8 @@ proc match(p: TRstParser, start: int, expr: string): bool =
else: else:
nil nil
else: else:
c = expr[i] var c = expr[i]
length = 0 var length = 0
while (i <= last) and (expr[i] == c): while (i <= last) and (expr[i] == c):
inc(i) inc(i)
inc(length) inc(length)
@ -688,25 +654,22 @@ proc match(p: TRstParser, start: int, expr: string): bool =
result = true result = true
proc fixupEmbeddedRef(n, a, b: PRstNode) = proc fixupEmbeddedRef(n, a, b: PRstNode) =
var sep, incr: int var sep = - 1
sep = - 1
for i in countdown(rsonsLen(n) - 2, 0): for i in countdown(rsonsLen(n) - 2, 0):
if n.sons[i].text == "<": if n.sons[i].text == "<":
sep = i sep = i
break break
if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): incr = 2 var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
else: incr = 1
for i in countup(0, sep - incr): addSon(a, n.sons[i]) for i in countup(0, sep - incr): addSon(a, n.sons[i])
for i in countup(sep + 1, rsonsLen(n) - 2): addSon(b, n.sons[i]) for i in countup(sep + 1, rsonsLen(n) - 2): addSon(b, n.sons[i])
proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode = proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
var a, b: PRstNode
result = n result = n
if isInlineMarkupEnd(p, "_"): if isInlineMarkupEnd(p, "_"):
inc(p.idx) inc(p.idx)
if (p.tok[p.idx - 2].symbol == "`") and (p.tok[p.idx - 3].symbol == ">"): if (p.tok[p.idx - 2].symbol == "`") and (p.tok[p.idx - 3].symbol == ">"):
a = newRstNode(rnInner) var a = newRstNode(rnInner)
b = newRstNode(rnInner) var b = newRstNode(rnInner)
fixupEmbeddedRef(n, a, b) fixupEmbeddedRef(n, a, b)
if rsonsLen(a) == 0: if rsonsLen(a) == 0:
result = newRstNode(rnStandaloneHyperlink) result = newRstNode(rnStandaloneHyperlink)
@ -799,33 +762,32 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
else: rstMessage(p, errXExpected, postfix) else: rstMessage(p, errXExpected, postfix)
proc parseInline(p: var TRstParser, father: PRstNode) = proc parseInline(p: var TRstParser, father: PRstNode) =
var n: PRstNode
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkPunct: of tkPunct:
if isInlineMarkupStart(p, "**"): if isInlineMarkupStart(p, "**"):
inc(p.idx) inc(p.idx)
n = newRstNode(rnStrongEmphasis) var n = newRstNode(rnStrongEmphasis)
parseUntil(p, n, "**", true) parseUntil(p, n, "**", true)
addSon(father, n) addSon(father, n)
elif isInlineMarkupStart(p, "*"): elif isInlineMarkupStart(p, "*"):
inc(p.idx) inc(p.idx)
n = newRstNode(rnEmphasis) var n = newRstNode(rnEmphasis)
parseUntil(p, n, "*", true) parseUntil(p, n, "*", true)
addSon(father, n) addSon(father, n)
elif isInlineMarkupStart(p, "``"): elif isInlineMarkupStart(p, "``"):
inc(p.idx) inc(p.idx)
n = newRstNode(rnInlineLiteral) var n = newRstNode(rnInlineLiteral)
parseUntil(p, n, "``", false) parseUntil(p, n, "``", false)
addSon(father, n) addSon(father, n)
elif isInlineMarkupStart(p, "`"): elif isInlineMarkupStart(p, "`"):
inc(p.idx) inc(p.idx)
n = newRstNode(rnInterpretedText) var n = newRstNode(rnInterpretedText)
parseUntil(p, n, "`", true) parseUntil(p, n, "`", true)
n = parsePostfix(p, n) n = parsePostfix(p, n)
addSon(father, n) addSon(father, n)
elif isInlineMarkupStart(p, "|"): elif isInlineMarkupStart(p, "|"):
inc(p.idx) inc(p.idx)
n = newRstNode(rnSubstitutionReferences) var n = newRstNode(rnSubstitutionReferences)
parseUntil(p, n, "|", false) parseUntil(p, n, "|", false)
addSon(father, n) addSon(father, n)
else: else:
@ -838,9 +800,8 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
else: assert(false) else: assert(false)
proc getDirective(p: var TRstParser): string = proc getDirective(p: var TRstParser): string =
var j: int
if (p.tok[p.idx].kind == tkWhite) and (p.tok[p.idx + 1].kind == tkWord): if (p.tok[p.idx].kind == tkWhite) and (p.tok[p.idx + 1].kind == tkWord):
j = p.idx var j = p.idx
inc(p.idx) inc(p.idx)
result = p.tok[p.idx].symbol result = p.tok[p.idx].symbol
inc(p.idx) inc(p.idx)
@ -859,13 +820,12 @@ proc getDirective(p: var TRstParser): string =
result = "" result = ""
proc parseComment(p: var TRstParser): PRstNode = proc parseComment(p: var TRstParser): PRstNode =
var indent: int
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkIndent, tkEof: of tkIndent, tkEof:
if p.tok[p.idx + 1].kind == tkIndent: if p.tok[p.idx + 1].kind == tkIndent:
inc(p.idx) # empty comment inc(p.idx) # empty comment
else: else:
indent = p.tok[p.idx].ival var indent = p.tok[p.idx].ival
while True: while True:
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkEof: of tkEof:
@ -903,18 +863,15 @@ proc parseLine(p: var TRstParser, father: PRstNode) =
proc parseSection(p: var TRstParser, result: PRstNode) proc parseSection(p: var TRstParser, result: PRstNode)
proc parseField(p: var TRstParser): PRstNode = proc parseField(p: var TRstParser): PRstNode =
var
col, indent: int
fieldname, fieldbody: PRstNode
result = newRstNode(rnField) result = newRstNode(rnField)
col = p.tok[p.idx].col var col = p.tok[p.idx].col
inc(p.idx) # skip : inc(p.idx) # skip :
fieldname = newRstNode(rnFieldname) var fieldname = newRstNode(rnFieldname)
parseUntil(p, fieldname, ":", false) parseUntil(p, fieldname, ":", false)
fieldbody = newRstNode(rnFieldbody) var fieldbody = newRstNode(rnFieldbody)
if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody) if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
if p.tok[p.idx].kind == tkIndent: if p.tok[p.idx].kind == tkIndent:
indent = p.tok[p.idx].ival var indent = p.tok[p.idx].ival
if indent > col: if indent > col:
pushInd(p, indent) pushInd(p, indent)
parseSection(p, fieldbody) parseSection(p, fieldbody)
@ -923,10 +880,9 @@ proc parseField(p: var TRstParser): PRstNode =
addSon(result, fieldbody) addSon(result, fieldbody)
proc parseFields(p: var TRstParser): PRstNode = proc parseFields(p: var TRstParser): PRstNode =
var col: int
result = nil result = nil
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx + 1].symbol == ":"): if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx + 1].symbol == ":"):
col = p.tok[p.idx].ival # BUGFIX! var col = p.tok[p.idx].ival # BUGFIX!
result = newRstNode(rnFieldList) result = newRstNode(rnFieldList)
inc(p.idx) inc(p.idx)
while true: while true:
@ -938,17 +894,15 @@ proc parseFields(p: var TRstParser): PRstNode =
break break
proc getFieldValue(n: PRstNode, fieldname: string): string = proc getFieldValue(n: PRstNode, fieldname: string): string =
var f: PRstNode
result = "" result = ""
if n.sons[1] == nil: return if n.sons[1] == nil: return
if (n.sons[1].kind != rnFieldList): if (n.sons[1].kind != rnFieldList):
InternalError("getFieldValue (2): " & rstnodeKindToStr[n.sons[1].kind]) InternalError("getFieldValue (2): " & $n.sons[1].kind)
for i in countup(0, rsonsLen(n.sons[1]) - 1): for i in countup(0, rsonsLen(n.sons[1]) - 1):
f = n.sons[1].sons[i] var f = n.sons[1].sons[i]
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
result = addNodes(f.sons[1]) result = addNodes(f.sons[1])
if result == "": if result == "": result = "\x01\x01" # indicates that the field exists
result = "\x01\x01" # indicates that the field exists
return return
proc getArgument(n: PRstNode): string = proc getArgument(n: PRstNode): string =
@ -957,13 +911,10 @@ proc getArgument(n: PRstNode): string =
proc parseDotDot(p: var TRstParser): PRstNode proc parseDotDot(p: var TRstParser): PRstNode
proc parseLiteralBlock(p: var TRstParser): PRstNode = proc parseLiteralBlock(p: var TRstParser): PRstNode =
var
indent: int
n: PRstNode
result = newRstNode(rnLiteralBlock) result = newRstNode(rnLiteralBlock)
n = newRstNode(rnLeaf, "") var n = newRstNode(rnLeaf, "")
if p.tok[p.idx].kind == tkIndent: if p.tok[p.idx].kind == tkIndent:
indent = p.tok[p.idx].ival var indent = p.tok[p.idx].ival
inc(p.idx) inc(p.idx)
while True: while True:
case p.tok[p.idx].kind case p.tok[p.idx].kind
@ -1003,8 +954,7 @@ proc tokenAfterNewline(p: TRstParser): int =
else: inc(result) else: inc(result)
proc isLineBlock(p: TRstParser): bool = proc isLineBlock(p: TRstParser): bool =
var j: int var j = tokenAfterNewline(p)
j = tokenAfterNewline(p)
result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
(p.tok[j].col > p.tok[p.idx].col) (p.tok[j].col > p.tok[p.idx].col)
@ -1015,8 +965,7 @@ proc predNL(p: TRstParser): bool =
(p.tok[p.idx - 1].ival == currInd(p)) (p.tok[p.idx - 1].ival == currInd(p))
proc isDefList(p: TRstParser): bool = proc isDefList(p: TRstParser): bool =
var j: int var j = tokenAfterNewline(p)
j = tokenAfterNewline(p)
result = (p.tok[p.idx].col < p.tok[j].col) and result = (p.tok[p.idx].col < p.tok[j].col) and
(p.tok[j].kind in {tkWord, tkOther, tkPunct}) and (p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
(p.tok[j - 2].symbol != "::") (p.tok[j - 2].symbol != "::")
@ -1063,17 +1012,14 @@ proc whichSection(p: TRstParser): TRstNodeKind =
else: result = rnLeaf else: result = rnLeaf
proc parseLineBlock(p: var TRstParser): PRstNode = proc parseLineBlock(p: var TRstParser): PRstNode =
var
col: int
item: PRstNode
result = nil result = nil
if p.tok[p.idx + 1].kind == tkWhite: if p.tok[p.idx + 1].kind == tkWhite:
col = p.tok[p.idx].col var col = p.tok[p.idx].col
result = newRstNode(rnLineBlock) result = newRstNode(rnLineBlock)
pushInd(p, p.tok[p.idx + 2].col) pushInd(p, p.tok[p.idx + 2].col)
inc(p.idx, 2) inc(p.idx, 2)
while true: while true:
item = newRstNode(rnLineBlockItem) var item = newRstNode(rnLineBlockItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) addSon(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
@ -1120,12 +1066,11 @@ proc parseParagraphWrapper(p: var TRstParser): PRstNode =
parseParagraph(p, result) parseParagraph(p, result)
proc parseHeadline(p: var TRstParser): PRstNode = proc parseHeadline(p: var TRstParser): PRstNode =
var c: Char
result = newRstNode(rnHeadline) result = newRstNode(rnHeadline)
parseLine(p, result) parseLine(p, result)
assert(p.tok[p.idx].kind == tkIndent) assert(p.tok[p.idx].kind == tkIndent)
assert(p.tok[p.idx + 1].kind == tkAdornment) assert(p.tok[p.idx + 1].kind == tkAdornment)
c = p.tok[p.idx + 1].symbol[0] var c = p.tok[p.idx + 1].symbol[0]
inc(p.idx, 2) inc(p.idx, 2)
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c) result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
@ -1136,8 +1081,7 @@ proc tokEnd(p: TRstParser): int =
result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
proc getColumns(p: var TRstParser, cols: var TIntSeq) = proc getColumns(p: var TRstParser, cols: var TIntSeq) =
var L: int var L = 0
L = 0
while true: while true:
inc(L) inc(L)
setlen(cols, L) setlen(cols, L)
@ -1177,8 +1121,8 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
if a != nil: if a != nil:
for j in countup(0, rsonsLen(a) - 1): a.sons[j].kind = rnTableHeaderCell for j in countup(0, rsonsLen(a) - 1): a.sons[j].kind = rnTableHeaderCell
if p.tok[p.idx].kind == tkEof: break if p.tok[p.idx].kind == tkEof: break
for j in countup(0, high(row)): for j in countup(0, high(row)): row[j] = ""
row[j] = "" # the following while loop iterates over the lines a single cell may span: # the following while loop iterates over the lines a single cell may span:
line = p.tok[p.idx].line line = p.tok[p.idx].line
while true: while true:
i = 0 i = 0
@ -1212,8 +1156,7 @@ proc parseTransition(p: var TRstParser): PRstNode =
if p.tok[p.idx].kind == tkIndent: inc(p.idx) if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseOverline(p: var TRstParser): PRstNode = proc parseOverline(p: var TRstParser): PRstNode =
var c: char var c = p.tok[p.idx].symbol[0]
c = p.tok[p.idx].symbol[0]
inc(p.idx, 2) inc(p.idx, 2)
result = newRstNode(rnOverline) result = newRstNode(rnOverline)
while true: while true:
@ -1232,19 +1175,15 @@ proc parseOverline(p: var TRstParser): PRstNode =
if p.tok[p.idx].kind == tkIndent: inc(p.idx) if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseBulletList(p: var TRstParser): PRstNode = proc parseBulletList(p: var TRstParser): PRstNode =
var
bullet: string
col: int
item: PRstNode
result = nil result = nil
if p.tok[p.idx + 1].kind == tkWhite: if p.tok[p.idx + 1].kind == tkWhite:
bullet = p.tok[p.idx].symbol var bullet = p.tok[p.idx].symbol
col = p.tok[p.idx].col var col = p.tok[p.idx].col
result = newRstNode(rnBulletList) result = newRstNode(rnBulletList)
pushInd(p, p.tok[p.idx + 2].col) pushInd(p, p.tok[p.idx + 2].col)
inc(p.idx, 2) inc(p.idx, 2)
while true: while true:
item = newRstNode(rnBulletItem) var item = newRstNode(rnBulletItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) addSon(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
@ -1256,23 +1195,20 @@ proc parseBulletList(p: var TRstParser): PRstNode =
popInd(p) popInd(p)
proc parseOptionList(p: var TRstParser): PRstNode = proc parseOptionList(p: var TRstParser): PRstNode =
var
a, b, c: PRstNode
j: int
result = newRstNode(rnOptionList) result = newRstNode(rnOptionList)
while true: while true:
if match(p, p.idx, "-w") or match(p, p.idx, "--w") or if match(p, p.idx, "-w") or match(p, p.idx, "--w") or
match(p, p.idx, "/w"): match(p, p.idx, "/w"):
a = newRstNode(rnOptionGroup) var a = newRstNode(rnOptionGroup)
b = newRstNode(rnDescription) var b = newRstNode(rnDescription)
c = newRstNode(rnOptionListItem) var c = newRstNode(rnOptionListItem)
while not (p.tok[p.idx].kind in {tkIndent, tkEof}): while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1): if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
inc(p.idx) inc(p.idx)
break break
addSon(a, newLeaf(p)) addSon(a, newLeaf(p))
inc(p.idx) inc(p.idx)
j = tokenAfterNewline(p) var j = tokenAfterNewline(p)
if (j > 0) and (p.tok[j - 1].kind == tkIndent) and if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
(p.tok[j - 1].ival > currInd(p)): (p.tok[j - 1].ival > currInd(p)):
pushInd(p, p.tok[j - 1].ival) pushInd(p, p.tok[j - 1].ival)
@ -1288,26 +1224,24 @@ proc parseOptionList(p: var TRstParser): PRstNode =
break break
proc parseDefinitionList(p: var TRstParser): PRstNode = proc parseDefinitionList(p: var TRstParser): PRstNode =
var
j, col: int
a, b, c: PRstNode
result = nil result = nil
j = tokenAfterNewLine(p) - 1 var j = tokenAfterNewLine(p) - 1
if (j >= 1) and (p.tok[j].kind == tkIndent) and if (j >= 1) and (p.tok[j].kind == tkIndent) and
(p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"): (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
col = p.tok[p.idx].col var col = p.tok[p.idx].col
result = newRstNode(rnDefList) result = newRstNode(rnDefList)
while true: while true:
j = p.idx j = p.idx
a = newRstNode(rnDefName) var a = newRstNode(rnDefName)
parseLine(p, a) #writeln('after def line: ', p.tok[p.idx].ival :1, ' ', col : 1); parseLine(p, a)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival > currInd(p)) and if (p.tok[p.idx].kind == tkIndent) and
(p.tok[p.idx].ival > currInd(p)) and
(p.tok[p.idx + 1].symbol != "::") and (p.tok[p.idx + 1].symbol != "::") and
not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}): not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
pushInd(p, p.tok[p.idx].ival) pushInd(p, p.tok[p.idx].ival)
b = newRstNode(rnDefBody) var b = newRstNode(rnDefBody)
parseSection(p, b) parseSection(p, b)
c = newRstNode(rnDefItem) var c = newRstNode(rnDefItem)
addSon(c, a) addSon(c, a)
addSon(c, b) addSon(c, b)
addSon(result, c) addSon(result, c)
@ -1329,23 +1263,20 @@ proc parseEnumList(p: var TRstParser): PRstNode =
const const
wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "] wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
wildpos: array[0..2, int] = [1, 0, 0] wildpos: array[0..2, int] = [1, 0, 0]
var
w, col, j: int
item: PRstNode
result = nil result = nil
w = 0 var w = 0
while w <= 2: while w <= 2:
if match(p, p.idx, wildcards[w]): break if match(p, p.idx, wildcards[w]): break
inc(w) inc(w)
if w <= 2: if w <= 2:
col = p.tok[p.idx].col var col = p.tok[p.idx].col
result = newRstNode(rnEnumList) result = newRstNode(rnEnumList)
inc(p.idx, wildpos[w] + 3) inc(p.idx, wildpos[w] + 3)
j = tokenAfterNewLine(p) var j = tokenAfterNewLine(p)
if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]): if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
pushInd(p, p.tok[p.idx].col) pushInd(p, p.tok[p.idx].col)
while true: while true:
item = newRstNode(rnEnumItem) var item = newRstNode(rnEnumItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) addSon(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
@ -1363,19 +1294,15 @@ proc sonKind(father: PRstNode, i: int): TRstNodeKind =
if i < rsonsLen(father): result = father.sons[i].kind if i < rsonsLen(father): result = father.sons[i].kind
proc parseSection(p: var TRstParser, result: PRstNode) = proc parseSection(p: var TRstParser, result: PRstNode) =
var
a: PRstNode
k: TRstNodeKind
leave: bool
while true: while true:
leave = false var leave = false
assert(p.idx >= 0) assert(p.idx >= 0)
while p.tok[p.idx].kind == tkIndent: while p.tok[p.idx].kind == tkIndent:
if currInd(p) == p.tok[p.idx].ival: if currInd(p) == p.tok[p.idx].ival:
inc(p.idx) inc(p.idx)
elif p.tok[p.idx].ival > currInd(p): elif p.tok[p.idx].ival > currInd(p):
pushInd(p, p.tok[p.idx].ival) pushInd(p, p.tok[p.idx].ival)
a = newRstNode(rnBlockQuote) var a = newRstNode(rnBlockQuote)
parseSection(p, a) parseSection(p, a)
addSon(result, a) addSon(result, a)
popInd(p) popInd(p)
@ -1384,39 +1311,27 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
break break
if leave: break if leave: break
if p.tok[p.idx].kind == tkEof: break if p.tok[p.idx].kind == tkEof: break
a = nil var a: PRstNode = nil
k = whichSection(p) var k = whichSection(p)
case k case k
of rnLiteralBlock: of rnLiteralBlock:
inc(p.idx) # skip '::' inc(p.idx) # skip '::'
a = parseLiteralBlock(p) a = parseLiteralBlock(p)
of rnBulletList: of rnBulletList: a = parseBulletList(p)
a = parseBulletList(p) of rnLineblock: a = parseLineBlock(p)
of rnLineblock: of rnDirective: a = parseDotDot(p)
a = parseLineBlock(p) of rnEnumList: a = parseEnumList(p)
of rnDirective: of rnLeaf: rstMessage(p, errNewSectionExpected)
a = parseDotDot(p) of rnParagraph: nil
of rnEnumList: of rnDefList: a = parseDefinitionList(p)
a = parseEnumList(p)
of rnLeaf:
rstMessage(p, errNewSectionExpected)
of rnParagraph:
nil
of rnDefList:
a = parseDefinitionList(p)
of rnFieldList: of rnFieldList:
dec(p.idx) dec(p.idx)
a = parseFields(p) a = parseFields(p)
of rnTransition: of rnTransition: a = parseTransition(p)
a = parseTransition(p) of rnHeadline: a = parseHeadline(p)
of rnHeadline: of rnOverline: a = parseOverline(p)
a = parseHeadline(p) of rnTable: a = parseSimpleTable(p)
of rnOverline: of rnOptionList: a = parseOptionList(p)
a = parseOverline(p)
of rnTable:
a = parseSimpleTable(p)
of rnOptionList:
a = parseOptionList(p)
else: InternalError("rst.parseSection()") else: InternalError("rst.parseSection()")
if (a == nil) and (k != rnDirective): if (a == nil) and (k != rnDirective):
a = newRstNode(rnParagraph) a = newRstNode(rnParagraph)
@ -1491,14 +1406,10 @@ proc dirInclude(p: var TRstParser): PRstNode =
# The text encoding of the external data file. Defaults to the document's # The text encoding of the external data file. Defaults to the document's
# encoding (if specified). # encoding (if specified).
# #
var
n: PRstNode
filename, path: string
q: TRstParser
result = nil result = nil
n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil) var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
filename = strip(addNodes(n.sons[0])) var filename = strip(addNodes(n.sons[0]))
path = findFile(filename) var path = findFile(filename)
if path == "": if path == "":
rstMessage(p, errCannotOpenFile, filename) rstMessage(p, errCannotOpenFile, filename)
else: else:
@ -1507,6 +1418,7 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = newRstNode(rnLiteralBlock) result = newRstNode(rnLiteralBlock)
addSon(result, newRstNode(rnLeaf, readFile(path))) addSon(result, newRstNode(rnLeaf, readFile(path)))
else: else:
var q: TRstParser
initParser(q, p.s) initParser(q, p.s)
q.filename = filename q.filename = filename
getTokens(readFile(path), false, q.tok) # workaround a GCC bug: getTokens(readFile(path), false, q.tok) # workaround a GCC bug:
@ -1515,15 +1427,12 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = parseDoc(q) result = parseDoc(q)
proc dirCodeBlock(p: var TRstParser): PRstNode = proc dirCodeBlock(p: var TRstParser): PRstNode =
var
n: PRstNode
filename, path: string
result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock) result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
filename = strip(getFieldValue(result, "file")) var filename = strip(getFieldValue(result, "file"))
if filename != "": if filename != "":
path = findFile(filename) var path = findFile(filename)
if path == "": rstMessage(p, errCannotOpenFile, filename) if path == "": rstMessage(p, errCannotOpenFile, filename)
n = newRstNode(rnLiteralBlock) var n = newRstNode(rnLiteralBlock)
addSon(n, newRstNode(rnLeaf, readFile(path))) addSon(n, newRstNode(rnLeaf, readFile(path)))
result.sons[2] = n result.sons[2] = n
result.kind = rnCodeBlock result.kind = rnCodeBlock
@ -1567,28 +1476,23 @@ proc dirRaw(p: var TRstParser): PRstNode =
# The text encoding of the external raw data (file or URL). # The text encoding of the external raw data (file or URL).
# Defaults to the document's encoding (if specified). # Defaults to the document's encoding (if specified).
# #
var filename, path, f: string
result = parseDirective(p, {hasOptions}, parseSectionWrapper) result = parseDirective(p, {hasOptions}, parseSectionWrapper)
result.kind = rnRaw result.kind = rnRaw
filename = getFieldValue(result, "file") var filename = getFieldValue(result, "file")
if filename != "": if filename != "":
path = findFile(filename) var path = findFile(filename)
if path == "": if path == "":
rstMessage(p, errCannotOpenFile, filename) rstMessage(p, errCannotOpenFile, filename)
else: else:
f = readFile(path) var f = readFile(path)
result = newRstNode(rnRaw) result = newRstNode(rnRaw)
addSon(result, newRstNode(rnLeaf, f)) addSon(result, newRstNode(rnLeaf, f))
proc parseDotDot(p: var TRstParser): PRstNode = proc parseDotDot(p: var TRstParser): PRstNode =
var
d: string
col: int
a, b: PRstNode
result = nil result = nil
col = p.tok[p.idx].col var col = p.tok[p.idx].col
inc(p.idx) inc(p.idx)
d = getDirective(p) var d = getDirective(p)
if d != "": if d != "":
pushInd(p, col) pushInd(p, col)
case getDirKind(d) case getDirKind(d)
@ -1606,14 +1510,15 @@ proc parseDotDot(p: var TRstParser): PRstNode =
elif match(p, p.idx, " _"): elif match(p, p.idx, " _"):
# hyperlink target: # hyperlink target:
inc(p.idx, 2) inc(p.idx, 2)
a = getReferenceName(p, ":") var a = getReferenceName(p, ":")
if p.tok[p.idx].kind == tkWhite: inc(p.idx) if p.tok[p.idx].kind == tkWhite: inc(p.idx)
b = untilEol(p) var b = untilEol(p)
setRef(p, rstnodeToRefname(a), b) setRef(p, rstnodeToRefname(a), b)
elif match(p, p.idx, " |"): elif match(p, p.idx, " |"):
# substitution definitions: # substitution definitions:
inc(p.idx, 2) inc(p.idx, 2)
a = getReferenceName(p, "|") var a = getReferenceName(p, "|")
var b: PRstNode
if p.tok[p.idx].kind == tkWhite: inc(p.idx) if p.tok[p.idx].kind == tkWhite: inc(p.idx)
if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0: if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
inc(p.idx) inc(p.idx)
@ -1628,32 +1533,28 @@ proc parseDotDot(p: var TRstParser): PRstNode =
elif match(p, p.idx, " ["): elif match(p, p.idx, " ["):
# footnotes, citations # footnotes, citations
inc(p.idx, 2) inc(p.idx, 2)
a = getReferenceName(p, "]") var a = getReferenceName(p, "]")
if p.tok[p.idx].kind == tkWhite: inc(p.idx) if p.tok[p.idx].kind == tkWhite: inc(p.idx)
b = untilEol(p) var b = untilEol(p)
setRef(p, rstnodeToRefname(a), b) setRef(p, rstnodeToRefname(a), b)
else: else:
result = parseComment(p) result = parseComment(p)
proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode = proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
var
x: int
y: PRstNode
e, key: string
result = n result = n
if n == nil: return if n == nil: return
case n.kind case n.kind
of rnSubstitutionReferences: of rnSubstitutionReferences:
x = findSub(p, n) var x = findSub(p, n)
if x >= 0: if x >= 0:
result = p.s.subs[x].value result = p.s.subs[x].value
else: else:
key = addNodes(n) var key = addNodes(n)
e = getEnv(key) var e = getEnv(key)
if e != "": result = newRstNode(rnLeaf, e) if e != "": result = newRstNode(rnLeaf, e)
else: rstMessage(p, warnUnknownSubstitutionX, key) else: rstMessage(p, warnUnknownSubstitutionX, key)
of rnRef: of rnRef:
y = findRef(p, rstnodeToRefname(n)) var y = findRef(p, rstnodeToRefname(n))
if y != nil: if y != nil:
result = newRstNode(rnHyperlink) result = newRstNode(rnHyperlink)
n.kind = rnInner n.kind = rnInner

View file

@ -139,18 +139,22 @@ proc fillToken*(L: var TToken)
proc isKeyword(kind: TTokType): bool = proc isKeyword(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isNimrodIdentifier*(s: string): bool =
if s[0] in SymStartChars:
for c in items(s):
if c notin SymChars: return
result = true
proc pushInd(L: var TLexer, indent: int) = proc pushInd(L: var TLexer, indent: int) =
var length: int var length = len(L.indentStack)
length = len(L.indentStack)
setlen(L.indentStack, length + 1) setlen(L.indentStack, length + 1)
if (indent > L.indentStack[length - 1]): if (indent > L.indentStack[length - 1]):
L.indentstack[length] = indent L.indentstack[length] = indent
else: else:
InternalError("pushInd") #writeln('push indent ', indent); InternalError("pushInd")
proc popInd(L: var TLexer) = proc popInd(L: var TLexer) =
var length: int var length = len(L.indentStack)
length = len(L.indentStack)
setlen(L.indentStack, length - 1) setlen(L.indentStack, length - 1)
proc findIdent(L: TLexer, indent: int): bool = proc findIdent(L: TLexer, indent: int): bool =
@ -161,12 +165,9 @@ proc findIdent(L: TLexer, indent: int): bool =
proc tokToStr(tok: PToken): string = proc tokToStr(tok: PToken): string =
case tok.tokType case tok.tokType
of tkIntLit..tkInt64Lit: of tkIntLit..tkInt64Lit: result = $tok.iNumber
result = $(tok.iNumber) of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
of tkFloatLit..tkFloat64Lit: of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
result = $(tok.fNumber)
of tkInvalid, tkStrLit..tkCharLit, tkComment:
result = tok.literal
of tkParLe..tkColon, tkEof, tkInd, tkSad, tkDed, tkAccent: of tkParLe..tkColon, tkEof, tkInd, tkSad, tkDed, tkAccent:
result = tokTypeToStr[tok.tokType] result = tokTypeToStr[tok.tokType]
else: else:

View file

@ -51,7 +51,9 @@ type
wLinksys, wDeprecated, wVarargs, wByref, wCallconv, wBreakpoint, wDebugger, wLinksys, wDeprecated, wVarargs, wByref, wCallconv, wBreakpoint, wDebugger,
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks, wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wW, wBoundchecks, wOverflowchecks, wNilchecks,
wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wWarnings, wW,
wHints, wOptimization, wSpeed, wSize, wNone, wPath, wP, wD, wU, wDebuginfo, wHints, wOptimization, wSpeed, wSize, wNone, wPath, wP, wD, wU, wDebuginfo,
wCompileonly, wNolinking, wForcebuild, wF, wDeadCodeElim, wSafecode, wCompileonly, wNolinking, wForcebuild, wF, wDeadCodeElim, wSafecode,
wCompileTime, wGc, wRefc, wBoehm, wA, wOpt, wO, wApp, wConsole, wGui, wCompileTime, wGc, wRefc, wBoehm, wA, wOpt, wO, wApp, wConsole, wGui,
@ -100,7 +102,10 @@ const
"byref", "callconv", "breakpoint", "debugger", "nimcall", "stdcall", "byref", "callconv", "breakpoint", "debugger", "nimcall", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
"noconv", "on", "off", "checks", "rangechecks", "boundchecks", "noconv", "on", "off", "checks", "rangechecks", "boundchecks",
"overflowchecks", "nilchecks", "assertions", "warnings", "w", "hints", "overflowchecks", "nilchecks",
"floatchecks", "nanchecks", "infchecks",
"assertions", "warnings", "w", "hints",
"optimization", "speed", "size", "none", "path", "p", "d", "u", "debuginfo", "optimization", "speed", "size", "none", "path", "p", "d", "u", "debuginfo",
"compileonly", "nolinking", "forcebuild", "f", "deadcodeelim", "safecode", "compileonly", "nolinking", "forcebuild", "f", "deadcodeelim", "safecode",
"compiletime", "gc", "refc", "boehm", "a", "opt", "o", "app", "console", "compiletime", "gc", "refc", "boehm", "a", "opt", "o", "app", "console",

5
start.bat Executable file
View file

@ -0,0 +1,5 @@
@echo off
REM COLOR 0A
SET NIMRODPATH=.
SET PATH=%NIMRODPATH%\bin;%NIMRODPATH%\dist\mingw\bin;%PATH%
cmd

1
tests/99bottles.nim Executable file
View file

@ -0,0 +1 @@
# Test if the compiler detects invalid module names

8
tests/tfloat1.nim Executable file
View file

@ -0,0 +1,8 @@
# Test new floating point exceptions
{.floatChecks: on.}
var x = 0.8
var y = 0.0
echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]

8
tests/tfloat2.nim Executable file
View file

@ -0,0 +1,8 @@
# Test new floating point exceptions
{.floatChecks: on.}
var x = 0.0
var y = 0.0
echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]