documented object constrs; endb works again
This commit is contained in:
parent
2b4922aea0
commit
a64d4dc35c
11 changed files with 152 additions and 143 deletions
|
|
@ -709,12 +709,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
|
||||||
rdLoc(test), strLit)
|
rdLoc(test), strLit)
|
||||||
|
|
||||||
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
if optFieldCheck in p.options:
|
||||||
var
|
var
|
||||||
a: TLoc
|
a: TLoc
|
||||||
f, field: PSym
|
f, field: PSym
|
||||||
ty: PType
|
ty: PType
|
||||||
r: PRope
|
r: PRope
|
||||||
if optFieldCheck in p.options:
|
|
||||||
ty = genRecordFieldAux(p, e.sons[0], d, a)
|
ty = genRecordFieldAux(p, e.sons[0], d, a)
|
||||||
r = rdLoc(a)
|
r = rdLoc(a)
|
||||||
f = e.sons[0].sons[1].sym
|
f = e.sons[0].sons[1].sym
|
||||||
|
|
@ -729,31 +729,6 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if field.loc.r == nil:
|
if field.loc.r == nil:
|
||||||
InternalError(e.info, "genCheckedRecordField") # generate the checks:
|
InternalError(e.info, "genCheckedRecordField") # generate the checks:
|
||||||
genFieldCheck(p, e, r, field)
|
genFieldCheck(p, e, r, field)
|
||||||
when false:
|
|
||||||
for i in countup(1, sonsLen(e) - 1):
|
|
||||||
it = e.sons[i]
|
|
||||||
assert(it.kind in nkCallKinds)
|
|
||||||
assert(it.sons[0].kind == nkSym)
|
|
||||||
op = it.sons[0].sym
|
|
||||||
if op.magic == mNot: it = it.sons[1]
|
|
||||||
assert(it.sons[2].kind == nkSym)
|
|
||||||
initLoc(test, locNone, it.typ, OnStack)
|
|
||||||
InitLocExpr(p, it.sons[1], u)
|
|
||||||
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
|
|
||||||
v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
|
|
||||||
genInExprAux(p, it, u, v, test)
|
|
||||||
id = NodeTableTestOrSet(p.module.dataCache,
|
|
||||||
newStrNode(nkStrLit, field.name.s), gBackendId)
|
|
||||||
if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
|
|
||||||
else: strLit = con("TMP", toRope(id))
|
|
||||||
if op.magic == mNot:
|
|
||||||
linefmt(p, cpsStmts,
|
|
||||||
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
|
||||||
rdLoc(test), strLit)
|
|
||||||
else:
|
|
||||||
linefmt(p, cpsStmts,
|
|
||||||
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
|
||||||
rdLoc(test), strLit)
|
|
||||||
app(r, rfmt(nil, ".$1", field.loc.r))
|
app(r, rfmt(nil, ".$1", field.loc.r))
|
||||||
putIntoDest(p, d, field.typ, r)
|
putIntoDest(p, d, field.typ, r)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
if t.kind == tyTuple:
|
if t.kind == tyTuple:
|
||||||
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
||||||
else:
|
else:
|
||||||
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple")
|
if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
|
||||||
field.r = ropef("$1.$2",
|
field.r = ropef("$1.$2",
|
||||||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||||
putLocIntoDest(p, v.loc, field)
|
putLocIntoDest(p, v.loc, field)
|
||||||
|
|
@ -64,19 +64,23 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
|
||||||
result = len(p.blocks)
|
result = len(p.blocks)
|
||||||
setlen(p.blocks, result + 1)
|
setlen(p.blocks, result + 1)
|
||||||
p.blocks[result].id = p.labels
|
p.blocks[result].id = p.labels
|
||||||
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
|
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
|
||||||
|
|
||||||
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
||||||
b.label = con("LA", b.id.toRope)
|
b.label = con("LA", b.id.toRope)
|
||||||
result = b.label
|
result = b.label
|
||||||
|
|
||||||
proc blockBody(b: var TBlock): PRope {.inline.} =
|
proc blockBody(b: var TBlock): PRope =
|
||||||
return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts])
|
result = b.sections[cpsLocals]
|
||||||
|
if b.frameLen > 0:
|
||||||
|
result.appf("F.len+=$1;$n", b.frameLen.toRope)
|
||||||
|
result.app(b.sections[cpsInit])
|
||||||
|
result.app(b.sections[cpsStmts])
|
||||||
|
|
||||||
proc endBlock(p: BProc, blockEnd: PRope) =
|
proc endBlock(p: BProc, blockEnd: PRope) =
|
||||||
let topBlock = p.blocks.len - 1
|
let topBlock = p.blocks.len-1
|
||||||
# the block is merged into the parent block
|
# the block is merged into the parent block
|
||||||
app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
||||||
setlen(p.blocks, topBlock)
|
setlen(p.blocks, topBlock)
|
||||||
# this is done after the block is popped so $n is
|
# this is done after the block is popped so $n is
|
||||||
# properly indented when pretty printing is enabled
|
# properly indented when pretty printing is enabled
|
||||||
|
|
@ -84,10 +88,13 @@ proc endBlock(p: BProc, blockEnd: PRope) =
|
||||||
|
|
||||||
proc endBlock(p: BProc) =
|
proc endBlock(p: BProc) =
|
||||||
let topBlock = p.blocks.len - 1
|
let topBlock = p.blocks.len - 1
|
||||||
let blockEnd = if p.blocks[topBlock].label != nil:
|
var blockEnd = if p.blocks[topBlock].label != nil:
|
||||||
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
|
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
|
||||||
else:
|
else:
|
||||||
~"}$n"
|
~"}$n"
|
||||||
|
let frameLen = p.blocks[topBlock].frameLen
|
||||||
|
if frameLen > 0:
|
||||||
|
blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
|
||||||
endBlock(p, blockEnd)
|
endBlock(p, blockEnd)
|
||||||
|
|
||||||
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||||
|
|
@ -800,12 +807,9 @@ proc genPragma(p: BProc, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
case whichPragma(it)
|
case whichPragma(it)
|
||||||
of wEmit:
|
of wEmit: genEmit(p, it)
|
||||||
genEmit(p, it)
|
of wBreakpoint: genBreakPoint(p, it)
|
||||||
of wBreakpoint:
|
of wWatchpoint: genWatchpoint(p, it)
|
||||||
genBreakPoint(p, it)
|
|
||||||
of wWatchpoint:
|
|
||||||
genWatchpoint(p, it)
|
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
|
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2013 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.
|
||||||
|
|
@ -276,11 +276,11 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
|
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
|
||||||
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
|
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
|
||||||
(p.prc == nil or sfPure notin p.prc.flags):
|
(p.prc == nil or sfPure notin p.prc.flags):
|
||||||
linefmt(p, cpsStmts, "#endb($1);$n", toRope(line))
|
linefmt(p, cpsStmts, "#endb($1, $2);$n",
|
||||||
|
line.toRope, makeCString(toFilename(t.info)))
|
||||||
elif ({optLineTrace, optStackTrace} * p.Options ==
|
elif ({optLineTrace, optStackTrace} * p.Options ==
|
||||||
{optLineTrace, optStackTrace}) and
|
{optLineTrace, optStackTrace}) and
|
||||||
(p.prc == nil or sfPure notin p.prc.flags):
|
(p.prc == nil or sfPure notin p.prc.flags):
|
||||||
|
|
||||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||||
line.toRope, t.info.quotedFilename)
|
line.toRope, t.info.quotedFilename)
|
||||||
|
|
||||||
|
|
@ -470,12 +470,13 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||||
# XXX work around a bug: No type information for open arrays possible:
|
# XXX work around a bug: No type information for open arrays possible:
|
||||||
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
|
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
|
||||||
var a = con("&", s.loc.r)
|
var a = con("&", s.loc.r)
|
||||||
if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
|
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
|
||||||
lineF(p, cpsInit,
|
lineF(p, cpsInit,
|
||||||
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
|
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
|
||||||
[toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
|
[p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
|
||||||
genTypeInfo(p.module, s.loc.t)])
|
genTypeInfo(p.module, s.loc.t)])
|
||||||
inc(p.frameLen)
|
inc(p.maxFrameLen)
|
||||||
|
inc p.blocks[p.blocks.len-1].frameLen
|
||||||
|
|
||||||
proc assignLocalVar(p: BProc, s: PSym) =
|
proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
#assert(s.loc.k == locNone) // not yet assigned
|
#assert(s.loc.k == locNone) // not yet assigned
|
||||||
|
|
@ -488,7 +489,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
if sfRegister in s.flags: app(decl, " register")
|
if sfRegister in s.flags: app(decl, " register")
|
||||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||||
# app(decl, " GC_GUARD")
|
# app(decl, " GC_GUARD")
|
||||||
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
|
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
|
||||||
app(decl, " volatile")
|
app(decl, " volatile")
|
||||||
appf(decl, " $1;$n", [s.loc.r])
|
appf(decl, " $1;$n", [s.loc.r])
|
||||||
line(p, cpsLocals, decl)
|
line(p, cpsLocals, decl)
|
||||||
|
|
@ -693,10 +694,11 @@ proc retIsNotVoid(s: PSym): bool =
|
||||||
|
|
||||||
proc initFrame(p: BProc, procname, filename: PRope): PRope =
|
proc initFrame(p: BProc, procname, filename: PRope): PRope =
|
||||||
discard cgsym(p.module, "pushFrame")
|
discard cgsym(p.module, "pushFrame")
|
||||||
if p.frameLen > 0:
|
if p.maxFrameLen > 0:
|
||||||
discard cgsym(p.module, "TVarSlot")
|
discard cgsym(p.module, "TVarSlot")
|
||||||
result = rfmt(nil, "\tnimfrs($1, $2, $3)$N",
|
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
|
||||||
procname, filename, p.frameLen.toRope)
|
procname, filename, p.maxFrameLen.toRope,
|
||||||
|
p.blocks[0].frameLen.toRope)
|
||||||
else:
|
else:
|
||||||
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
|
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,10 @@ type
|
||||||
id*: int # the ID of the label; positive means that it
|
id*: int # the ID of the label; positive means that it
|
||||||
label*: PRope # generated text for the label
|
label*: PRope # generated text for the label
|
||||||
# nil if label is not used
|
# nil if label is not used
|
||||||
nestedTryStmts*: int # how many try statements is it nested into
|
|
||||||
sections*: TCProcSections # the code beloging
|
sections*: TCProcSections # the code beloging
|
||||||
isLoop*: bool # whether block is a loop
|
isLoop*: bool # whether block is a loop
|
||||||
|
nestedTryStmts*: int16 # how many try statements is it nested into
|
||||||
|
frameLen*: int16
|
||||||
|
|
||||||
TCProc{.final.} = object # represents C proc that is currently generated
|
TCProc{.final.} = object # represents C proc that is currently generated
|
||||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
prc*: PSym # the Nimrod proc that this C proc belongs to
|
||||||
|
|
@ -74,9 +75,7 @@ type
|
||||||
options*: TOptions # options that should be used for code
|
options*: TOptions # options that should be used for code
|
||||||
# generation; this is the same as prc.options
|
# generation; this is the same as prc.options
|
||||||
# unless prc == nil
|
# unless prc == nil
|
||||||
frameLen*: int # current length of frame descriptor
|
maxFrameLen*: int # max length of frame descriptor
|
||||||
sendClosure*: PType # closure record type that we pass
|
|
||||||
receiveClosure*: PType # closure record type that we get
|
|
||||||
module*: BModule # used to prevent excessive parameter passing
|
module*: BModule # used to prevent excessive parameter passing
|
||||||
withinLoop*: int # > 0 if we are within a loop
|
withinLoop*: int # > 0 if we are within a loop
|
||||||
gcFrameId*: natural # for the GC stack marking
|
gcFrameId*: natural # for the GC stack marking
|
||||||
|
|
|
||||||
|
|
@ -984,7 +984,7 @@ in future versions of the compiler.
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
type
|
type
|
||||||
TPerson = tuple[name: string, age: int] # type representing a person
|
TPerson = tuple[name: string, age: int] # type representing a person:
|
||||||
# a person consists of a name
|
# a person consists of a name
|
||||||
# and an age
|
# and an age
|
||||||
var
|
var
|
||||||
|
|
@ -1000,7 +1000,6 @@ For consistency with ``object`` declarations, tuples in a ``type`` section
|
||||||
can also be defined with indentation instead of ``[]``:
|
can also be defined with indentation instead of ``[]``:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
type
|
type
|
||||||
TPerson = tuple # type representing a person
|
TPerson = tuple # type representing a person
|
||||||
name: string # a person consists of a name
|
name: string # a person consists of a name
|
||||||
|
|
@ -1011,7 +1010,6 @@ and information hiding. Objects have access to their type at runtime, so that
|
||||||
the ``of`` operator can be used to determine the object's type.
|
the ``of`` operator can be used to determine the object's type.
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
type
|
type
|
||||||
TPerson {.inheritable.} = object
|
TPerson {.inheritable.} = object
|
||||||
name*: string # the * means that `name` is accessible from other modules
|
name*: string # the * means that `name` is accessible from other modules
|
||||||
|
|
@ -1032,6 +1030,19 @@ and thus have no hidden type field. One can use the ``inheritable`` pragma to
|
||||||
introduce new object roots apart from ``system.TObject``.
|
introduce new object roots apart from ``system.TObject``.
|
||||||
|
|
||||||
|
|
||||||
|
Object construction
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Objects can also be created with an `object construction expression`:idx: that
|
||||||
|
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
|
||||||
|
an ``object`` type or a ``ref object`` type:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
var student = TStudent(name: "Anton", age: 5, id: 3)
|
||||||
|
|
||||||
|
For a ``ref object`` type ``new`` is invoked implicitly.
|
||||||
|
|
||||||
|
|
||||||
Object variants
|
Object variants
|
||||||
---------------
|
---------------
|
||||||
Often an object hierarchy is overkill in certain situations where simple
|
Often an object hierarchy is overkill in certain situations where simple
|
||||||
|
|
@ -1061,16 +1072,23 @@ An example:
|
||||||
of nkIf:
|
of nkIf:
|
||||||
condition, thenPart, elsePart: PNode
|
condition, thenPart, elsePart: PNode
|
||||||
|
|
||||||
var
|
# create a new case object:
|
||||||
n: PNode
|
var n = PNode(kind: nkIf, condition: nil)
|
||||||
new(n) # creates a new node
|
# accessing n.thenPart is valid because the ``nkIf`` branch is active:
|
||||||
n.kind = nkFloat
|
n.thenPart = PNode(kind: nkFloat, floatVal: 2.0)
|
||||||
n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``, so that it fits
|
|
||||||
|
|
||||||
# the following statement raises an `EInvalidField` exception, because
|
# the following statement raises an `EInvalidField` exception, because
|
||||||
# n.kind's value does not fit:
|
# n.kind's value does not fit and the ``nkString`` branch is not active:
|
||||||
n.strVal = ""
|
n.strVal = ""
|
||||||
|
|
||||||
|
# invalid: would change the active object branch:
|
||||||
|
n.kind = nkInt
|
||||||
|
|
||||||
|
var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
|
||||||
|
rightOp: PNode(kind: nkInt, intVal: 2))
|
||||||
|
# valid: does not change the active object branch:
|
||||||
|
x.kind = nkSub
|
||||||
|
|
||||||
As can been seen from the example, an advantage to an object hierarchy is that
|
As can been seen from the example, an advantage to an object hierarchy is that
|
||||||
no casting between different object types is needed. Yet, access to invalid
|
no casting between different object types is needed. Yet, access to invalid
|
||||||
object fields raises an exception.
|
object fields raises an exception.
|
||||||
|
|
@ -1078,6 +1096,11 @@ object fields raises an exception.
|
||||||
The syntax of ``case`` in an object declaration follows closely the syntax of
|
The syntax of ``case`` in an object declaration follows closely the syntax of
|
||||||
the ``case`` statement: The branches in a ``case`` section may be indented too.
|
the ``case`` statement: The branches in a ``case`` section may be indented too.
|
||||||
|
|
||||||
|
In the example the ``kind`` field is called the `discriminator`:idx:\: For
|
||||||
|
safety its address cannot be taken and assignments to it are restricted: The
|
||||||
|
new value must not lead to a change of the active object branch. For an object
|
||||||
|
branch switch ``system.reset`` has to be used.
|
||||||
|
|
||||||
|
|
||||||
Set type
|
Set type
|
||||||
--------
|
--------
|
||||||
|
|
@ -2387,6 +2410,7 @@ the proc's name.
|
||||||
Procs as expressions can appear both as nested procs and inside top level
|
Procs as expressions can appear both as nested procs and inside top level
|
||||||
executable code.
|
executable code.
|
||||||
|
|
||||||
|
|
||||||
Do notation
|
Do notation
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
@ -2410,7 +2434,7 @@ Again, let's see the equivalent of the previous example:
|
||||||
sort(cities) do (x,y: string) -> int:
|
sort(cities) do (x,y: string) -> int:
|
||||||
cmp(x.len, y.len)
|
cmp(x.len, y.len)
|
||||||
|
|
||||||
Finally, more than one ``do`` blocks can appear in a single call:
|
Finally, more than one ``do`` block can appear in a single call:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc performWithUndo(task: proc(), undo: proc()) = ...
|
proc performWithUndo(task: proc(), undo: proc()) = ...
|
||||||
|
|
@ -2426,6 +2450,7 @@ omitted if the supplied proc doesn't have any parameters and return value.
|
||||||
The compatibility works in the other direction too as the ``do`` syntax can be
|
The compatibility works in the other direction too as the ``do`` syntax can be
|
||||||
used with macros and templates expecting ``stmt`` blocks.
|
used with macros and templates expecting ``stmt`` blocks.
|
||||||
|
|
||||||
|
|
||||||
Nonoverloadable builtins
|
Nonoverloadable builtins
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
@ -2987,8 +3012,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
|
||||||
raise ``system.E_Base`` unless ``q`` has an explicit ``raises`` list.
|
raise ``system.E_Base`` unless ``q`` has an explicit ``raises`` list.
|
||||||
3. Every call to a method ``m`` is assumed to
|
3. Every call to a method ``m`` is assumed to
|
||||||
raise ``system.E_Base`` unless ``m`` has an explicit ``raises`` list.
|
raise ``system.E_Base`` unless ``m`` has an explicit ``raises`` list.
|
||||||
4. For every other call the analysis can determine an
|
4. For every other call the analysis can determine an exact ``raises`` list.
|
||||||
exact ``raises`` list.
|
|
||||||
5. For determining a ``raises`` list, the ``raise`` and ``try`` statements
|
5. For determining a ``raises`` list, the ``raise`` and ``try`` statements
|
||||||
of ``p`` are taken into consideration.
|
of ``p`` are taken into consideration.
|
||||||
|
|
||||||
|
|
@ -3259,7 +3283,7 @@ Symbol lookup in generics
|
||||||
|
|
||||||
The symbol binding rules in generics are slightly subtle: There are "open" and
|
The symbol binding rules in generics are slightly subtle: There are "open" and
|
||||||
"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
|
"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
|
||||||
context, an "open" symbol can be. Per default overloaded symbols are open
|
context, an "open" symbol can. Per default overloaded symbols are open
|
||||||
and every other symbol is closed.
|
and every other symbol is closed.
|
||||||
|
|
||||||
Open symbols are looked up in two different contexts: Both the context
|
Open symbols are looked up in two different contexts: Both the context
|
||||||
|
|
@ -4106,8 +4130,8 @@ implemented with term rewriting:
|
||||||
proc p(x, y: int; cond: bool): int =
|
proc p(x, y: int; cond: bool): int =
|
||||||
result = if cond: x + y else: x - y
|
result = if cond: x + y else: x - y
|
||||||
|
|
||||||
template optP{p(x, y, true)}(x, y: expr): expr = x + y
|
template optP1{p(x, y, true)}(x, y: expr): expr = x + y
|
||||||
template optP{p(x, y, false)}(x, y: expr): expr = x - y
|
template optP2{p(x, y, false)}(x, y: expr): expr = x - y
|
||||||
|
|
||||||
|
|
||||||
Example: hoisting
|
Example: hoisting
|
||||||
|
|
|
||||||
41
doc/tut2.txt
41
doc/tut2.txt
|
|
@ -46,8 +46,7 @@ Objects
|
||||||
Like tuples, objects are a means to pack different values together in a
|
Like tuples, objects are a means to pack different values together in a
|
||||||
structured way. However, objects provide many features that tuples do not:
|
structured way. However, objects provide many features that tuples do not:
|
||||||
They provide inheritance and information hiding. Because objects encapsulate
|
They provide inheritance and information hiding. Because objects encapsulate
|
||||||
data, the ``()`` tuple constructor cannot be used to construct objects. So
|
data, the ``T()`` object constructor should only be used internally and the
|
||||||
the order of the object's fields is not as important as it is for tuples. The
|
|
||||||
programmer should provide a proc to initialize the object (this is called
|
programmer should provide a proc to initialize the object (this is called
|
||||||
a *constructor*).
|
a *constructor*).
|
||||||
|
|
||||||
|
|
@ -55,7 +54,6 @@ Objects have access to their type at runtime. There is an
|
||||||
``of`` operator that can be used to check the object's type:
|
``of`` operator that can be used to check the object's type:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
type
|
type
|
||||||
TPerson = object of TObject
|
TPerson = object of TObject
|
||||||
name*: string # the * means that `name` is accessible from other modules
|
name*: string # the * means that `name` is accessible from other modules
|
||||||
|
|
@ -68,6 +66,8 @@ Objects have access to their type at runtime. There is an
|
||||||
student: TStudent
|
student: TStudent
|
||||||
person: TPerson
|
person: TPerson
|
||||||
assert(student of TStudent) # is true
|
assert(student of TStudent) # is true
|
||||||
|
# object construction:
|
||||||
|
student = TStudent(name: "Anton", age: 5, id: 2)
|
||||||
|
|
||||||
Object fields that should be visible from outside the defining module have to
|
Object fields that should be visible from outside the defining module have to
|
||||||
be marked by ``*``. In contrast to tuples, different object types are
|
be marked by ``*``. In contrast to tuples, different object types are
|
||||||
|
|
@ -161,12 +161,7 @@ An example:
|
||||||
of nkIf:
|
of nkIf:
|
||||||
condition, thenPart, elsePart: PNode
|
condition, thenPart, elsePart: PNode
|
||||||
|
|
||||||
var
|
var n = PNode(kind: nkFloat, floatVal: 1.0)
|
||||||
n: PNode
|
|
||||||
new(n) # creates a new node
|
|
||||||
n.kind = nkFloat
|
|
||||||
n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``
|
|
||||||
|
|
||||||
# the following statement raises an `EInvalidField` exception, because
|
# the following statement raises an `EInvalidField` exception, because
|
||||||
# n.kind's value does not fit:
|
# n.kind's value does not fit:
|
||||||
n.strVal = ""
|
n.strVal = ""
|
||||||
|
|
@ -288,30 +283,22 @@ Procedures always use static dispatch. For dynamic dispatch replace the
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
TExpr = object of TObject ## abstract base class for an expression
|
PExpr = ref object of TObject ## abstract base class for an expression
|
||||||
TLiteral = object of TExpr
|
PLiteral = ref object of PExpr
|
||||||
x: int
|
x: int
|
||||||
TPlusExpr = object of TExpr
|
PPlusExpr = ref object of PExpr
|
||||||
a, b: ref TExpr
|
a, b: PExpr
|
||||||
|
|
||||||
method eval(e: ref TExpr): int =
|
# watch out: 'eval' relies on dynamic binding
|
||||||
|
method eval(e: PExpr): int =
|
||||||
# override this base method
|
# override this base method
|
||||||
quit "to override!"
|
quit "to override!"
|
||||||
|
|
||||||
method eval(e: ref TLiteral): int = return e.x
|
method eval(e: PLiteral): int = e.x
|
||||||
|
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
|
||||||
|
|
||||||
method eval(e: ref TPlusExpr): int =
|
proc newLit(x: int): PLiteral = PLiteral(x: x)
|
||||||
# watch out: relies on dynamic binding
|
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
|
||||||
return eval(e.a) + eval(e.b)
|
|
||||||
|
|
||||||
proc newLit(x: int): ref TLiteral =
|
|
||||||
new(result)
|
|
||||||
result.x = x
|
|
||||||
|
|
||||||
proc newPlus(a, b: ref TExpr): ref TPlusExpr =
|
|
||||||
new(result)
|
|
||||||
result.a = a
|
|
||||||
result.b = b
|
|
||||||
|
|
||||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
||||||
|
|
||||||
|
|
|
||||||
17
examples/debugging.nim
Normal file
17
examples/debugging.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Simple program to test the debugger
|
||||||
|
# compile with --debugger:on
|
||||||
|
|
||||||
|
proc someComp(x, y: int): int =
|
||||||
|
let a = x+y
|
||||||
|
if a > 7:
|
||||||
|
let b = a*90
|
||||||
|
{.breakpoint.}
|
||||||
|
result = b
|
||||||
|
{.breakpoint.}
|
||||||
|
|
||||||
|
proc pp() =
|
||||||
|
var aa = 45
|
||||||
|
var bb = "abcdef"
|
||||||
|
echo someComp(23, 45)
|
||||||
|
|
||||||
|
pp()
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Nimrod's Runtime Library
|
Nimrod's Runtime Library
|
||||||
(c) Copyright 2012 Andreas Rumpf
|
(c) Copyright 2013 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.
|
||||||
|
|
@ -440,9 +440,9 @@ struct TFrame {
|
||||||
volatile TFrame F; \
|
volatile TFrame F; \
|
||||||
F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
|
F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
|
||||||
|
|
||||||
#define nimfrs(proc, file, slots) \
|
#define nimfrs(proc, file, slots, length) \
|
||||||
volatile struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
|
volatile struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
|
||||||
F.procname = proc; F.filename = file; F.line = 0; F.len = slots; nimFrame((TFrame*)&F);
|
F.procname = proc; F.filename = file; F.line = 0; F.len = length; nimFrame((TFrame*)&F);
|
||||||
|
|
||||||
#define nimln(n, file) \
|
#define nimln(n, file) \
|
||||||
F.line = n; F.filename = file;
|
F.line = n; F.filename = file;
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,8 @@ proc fileMatches(c, bp: cstring): bool =
|
||||||
return false
|
return false
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < blen:
|
while i < blen:
|
||||||
var x, y: char
|
var x = bp[i]
|
||||||
x = bp[i]
|
var y = c[i+clen-blen]
|
||||||
y = c[i+clen-blen]
|
|
||||||
when FileSystemCaseInsensitive:
|
when FileSystemCaseInsensitive:
|
||||||
if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
|
if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
|
||||||
if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
|
if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
|
||||||
|
|
@ -742,7 +741,7 @@ proc checkWatchpoints =
|
||||||
debugOut(Watchpoints[i].name)
|
debugOut(Watchpoints[i].name)
|
||||||
Watchpoints[i].oldValue = newHash
|
Watchpoints[i].oldValue = newHash
|
||||||
|
|
||||||
proc endb(line: int) {.compilerproc.} =
|
proc endb(line: int, file: cstring) {.compilerproc.} =
|
||||||
# This proc is called before every Nimrod code line!
|
# This proc is called before every Nimrod code line!
|
||||||
# Thus, it must have as few parameters as possible to keep the
|
# Thus, it must have as few parameters as possible to keep the
|
||||||
# code size small!
|
# code size small!
|
||||||
|
|
@ -753,6 +752,7 @@ proc endb(line: int) {.compilerproc.} =
|
||||||
#if oldState != dbOff:
|
#if oldState != dbOff:
|
||||||
checkWatchpoints()
|
checkWatchpoints()
|
||||||
framePtr.line = line # this is done here for smaller code size!
|
framePtr.line = line # this is done here for smaller code size!
|
||||||
|
framePtr.filename = file
|
||||||
if dbgLineHook != nil: dbgLineHook()
|
if dbgLineHook != nil: dbgLineHook()
|
||||||
case oldState
|
case oldState
|
||||||
of dbStepInto:
|
of dbStepInto:
|
||||||
|
|
@ -765,7 +765,8 @@ proc endb(line: int) {.compilerproc.} =
|
||||||
CommandPrompt()
|
CommandPrompt()
|
||||||
else: # breakpoints are wanted though (I guess)
|
else: # breakpoints are wanted though (I guess)
|
||||||
checkForBreakpoint()
|
checkForBreakpoint()
|
||||||
of dbBreakpoints: # debugger is only interested in breakpoints
|
of dbBreakpoints:
|
||||||
|
# debugger is only interested in breakpoints
|
||||||
checkForBreakpoint()
|
checkForBreakpoint()
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
|
|
|
||||||
51
todo.txt
51
todo.txt
|
|
@ -1,6 +1,9 @@
|
||||||
version 0.9.2
|
version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
- fix destructors; don't work yet when used as expression; alternative for
|
||||||
|
version 1: disallow expressions yielding a type with a destructor that are
|
||||||
|
not in a 'let/var' context (p(a.openFile, b.openFile) makes no sense anyway)
|
||||||
- lazy overloading resolution:
|
- lazy overloading resolution:
|
||||||
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
||||||
* special case ``tyStmt``
|
* special case ``tyStmt``
|
||||||
|
|
@ -8,16 +11,24 @@ version 0.9.2
|
||||||
* test libffi on windows
|
* test libffi on windows
|
||||||
* test: times.format with the FFI
|
* test: times.format with the FFI
|
||||||
- acyclic vs prunable; introduce GC hints
|
- acyclic vs prunable; introduce GC hints
|
||||||
- implement constructors
|
|
||||||
- more checks
|
|
||||||
- document them
|
|
||||||
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
||||||
- fix:
|
|
||||||
- 'result' is not properly cleaned for NRVO
|
|
||||||
- document NimMain and check whether it works for threading
|
- document NimMain and check whether it works for threading
|
||||||
- fix destructors; don't work yet when used as expression; alternative for
|
|
||||||
version 1: disallow expressions yielding a type with a destructor that are
|
|
||||||
not in a 'let/var' context (p(a.openFile, b.openFile) makes no sense anyway)
|
Bugs
|
||||||
|
====
|
||||||
|
|
||||||
|
- 'result' is not properly cleaned for NRVO
|
||||||
|
- instantiated generics are listed in error messages
|
||||||
|
- sneaking with qualifiedLookup() is really broken!
|
||||||
|
- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' --
|
||||||
|
use a qualifier
|
||||||
|
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||||
|
- JS gen: fix exception handling
|
||||||
|
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||||
|
in c++ mode)
|
||||||
|
- bootstrapping does not work in C++ mode
|
||||||
|
- case statement exhaustiveness checking is still wrong
|
||||||
|
|
||||||
|
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
|
|
@ -40,7 +51,7 @@ version 0.9.X
|
||||||
- test&finish first class iterators:
|
- test&finish first class iterators:
|
||||||
* nested iterators
|
* nested iterators
|
||||||
- implement the missing features wrt inheritance
|
- implement the missing features wrt inheritance
|
||||||
- better support for *hard* realtime systems
|
- object pooling support for *hard* realtime systems
|
||||||
- improve the compiler as a service
|
- improve the compiler as a service
|
||||||
- better support for macros that rewrite procs
|
- better support for macros that rewrite procs
|
||||||
- macros need access to types and symbols (partially implemented)
|
- macros need access to types and symbols (partially implemented)
|
||||||
|
|
@ -71,8 +82,9 @@ version 0.9.XX
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- object branch transitions can't work with the current 'reset'; add a 'reset'
|
- object branch transitions can't work with the current 'reset'; add a 'reset'
|
||||||
with an additional parameter --> re-evaluate this issue after constructors
|
with an additional parameter --> simple:
|
||||||
have been added
|
provide a 'reset(x, TObj(k: nkValue))' instead? why bother? '=' does the
|
||||||
|
same.
|
||||||
- document nimdoc properly finally
|
- document nimdoc properly finally
|
||||||
- make 'clamp' a magic for the range stuff
|
- make 'clamp' a magic for the range stuff
|
||||||
- better type syntax for functions and tuples: tuple(int, int); (int,int)->int
|
- better type syntax for functions and tuples: tuple(int, int); (int,int)->int
|
||||||
|
|
@ -103,6 +115,8 @@ Not essential for 1.0.0
|
||||||
* first version: mark black in write barrier
|
* first version: mark black in write barrier
|
||||||
* second version: introduce fake roots instead of marking black
|
* second version: introduce fake roots instead of marking black
|
||||||
* third version: find some clever heuristic which is preferable
|
* third version: find some clever heuristic which is preferable
|
||||||
|
- object constructors: static check for fields if discriminator is known at
|
||||||
|
compile time
|
||||||
|
|
||||||
|
|
||||||
GC
|
GC
|
||||||
|
|
@ -122,18 +136,3 @@ Optimizations
|
||||||
even further write barrier specialization
|
even further write barrier specialization
|
||||||
- inlining of first class functions
|
- inlining of first class functions
|
||||||
- proc specialization in the code gen for write barrier specialization
|
- proc specialization in the code gen for write barrier specialization
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
|
||||||
====
|
|
||||||
|
|
||||||
- instantiated generics are listed in error messages
|
|
||||||
- sneaking with qualifiedLookup() is really broken!
|
|
||||||
- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' --
|
|
||||||
use a qualifier
|
|
||||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
|
||||||
- JS gen: fix exception handling
|
|
||||||
- the better scoping for locals is the wrong default for endb
|
|
||||||
- osproc execProcesses can deadlock if all processes fail (as experienced
|
|
||||||
in c++ mode)
|
|
||||||
- case statement exhaustiveness checking is still wrong
|
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,17 @@ Bugfixes
|
||||||
with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time
|
with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time
|
||||||
or not at all. There is also a new GC you can activate
|
or not at all. There is also a new GC you can activate
|
||||||
with ``--gc:markAndSweep`` which does not have this problem but is slower in
|
with ``--gc:markAndSweep`` which does not have this problem but is slower in
|
||||||
general.
|
general and has no realtime guarantees.
|
||||||
|
|
||||||
|
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- There is a new experimental mark&sweep GC which can be faster (or much
|
||||||
|
slower) than the default GC. Enable with ``--gc:markAndSweep``.
|
||||||
- Added ``system.onRaise`` to support a condition system.
|
- Added ``system.onRaise`` to support a condition system.
|
||||||
- Added ``macros.quote`` for AST quasi-quoting.
|
- Added ``macros.quote`` for AST quasi-quoting.
|
||||||
- Added ``system.unsafeNew`` to support hacky variable length objects.
|
- Added ``system.unsafeNew`` to support hacky variable length objects.
|
||||||
- There is a new experimental mark&sweep GC which can be faster (or much
|
|
||||||
slower) than the default GC. Enable with ``--gc:markAndSweep``.
|
|
||||||
- ``system.fields`` and ``system.fieldPairs`` support ``object`` too; they
|
- ``system.fields`` and ``system.fieldPairs`` support ``object`` too; they
|
||||||
used to only support tuples.
|
used to only support tuples.
|
||||||
|
|
||||||
|
|
@ -68,6 +68,7 @@ Language Additions
|
||||||
dependencies explicitly.
|
dependencies explicitly.
|
||||||
- Overloading based on ASTs has been implemented.
|
- Overloading based on ASTs has been implemented.
|
||||||
- Generics are now supported for multi methods.
|
- Generics are now supported for multi methods.
|
||||||
|
- Objects can be initialized via an *object constructor expression*.
|
||||||
|
|
||||||
|
|
||||||
2012-09-23 Version 0.9.0 released
|
2012-09-23 Version 0.9.0 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue