objects with no ancestor are not implicitely final
This commit is contained in:
parent
afcff024a1
commit
d17caa86e8
15 changed files with 44 additions and 22 deletions
|
|
@ -305,7 +305,7 @@ type
|
||||||
tyBigNum,
|
tyBigNum,
|
||||||
tyConst, tyMutable, tyVarargs,
|
tyConst, tyMutable, tyVarargs,
|
||||||
tyIter, # unused
|
tyIter, # unused
|
||||||
tyProxy # currently unused
|
tyProxy # used as errornous type (for idetools)
|
||||||
tyTypeClass,
|
tyTypeClass,
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -328,10 +328,11 @@ type
|
||||||
nfSem # node has been checked for semantics
|
nfSem # node has been checked for semantics
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 15 for efficiency reasons (now: 13)
|
TTypeFlag* = enum # keep below 15 for efficiency reasons (now: 14)
|
||||||
tfVarargs, # procedure has C styled varargs
|
tfVarargs, # procedure has C styled varargs
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
tfFinal, # is the object final?
|
tfFinal, # is the object final?
|
||||||
|
tfInheritable, # is the object inheritable?
|
||||||
tfAcyclic, # type is acyclic (for GC optimization)
|
tfAcyclic, # type is acyclic (for GC optimization)
|
||||||
tfEnumHasHoles, # enum cannot be mapped into a range
|
tfEnumHasHoles, # enum cannot be mapped into a range
|
||||||
tfShallow, # type can be shallow copied on assignment
|
tfShallow, # type can be shallow copied on assignment
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ proc InitDefines*() =
|
||||||
DefineSymbol("nimrod") # 'nimrod' is always defined
|
DefineSymbol("nimrod") # 'nimrod' is always defined
|
||||||
# for bootstrapping purposes and old code:
|
# for bootstrapping purposes and old code:
|
||||||
DefineSymbol("nimhygiene")
|
DefineSymbol("nimhygiene")
|
||||||
|
DefineSymbol("niminheritable")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
case targetCPU
|
case targetCPU
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
|
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||||
wGenSym, wInject}
|
wInheritable, wGenSym, wInject}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc, wError}
|
wImportcpp, wImportobjc, wError}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
|
|
@ -584,7 +584,11 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
else: incl(sym.typ.flags, tfFinal)
|
else: incl(sym.typ.flags, tfFinal)
|
||||||
of wAcyclic:
|
of wInheritable:
|
||||||
|
noVal(it)
|
||||||
|
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
|
||||||
|
else: incl(sym.typ.flags, tfInheritable)
|
||||||
|
of wAcyclic:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
else: incl(sym.typ.flags, tfAcyclic)
|
else: incl(sym.typ.flags, tfAcyclic)
|
||||||
|
|
|
||||||
|
|
@ -545,6 +545,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c)
|
var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c)
|
||||||
s.typ = result
|
s.typ = result
|
||||||
pragma(c, s, n.sons[0], typePragmas)
|
pragma(c, s, n.sons[0], typePragmas)
|
||||||
|
if base == nil and tfInheritable notin result.flags:
|
||||||
|
incl(result.flags, tfFinal)
|
||||||
|
|
||||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
||||||
|
|
|
||||||
|
|
@ -970,9 +970,10 @@ in future versions of the compiler.
|
||||||
person = ("Peter", 30)
|
person = ("Peter", 30)
|
||||||
|
|
||||||
The implementation aligns the fields for best access performance. The alignment
|
The implementation aligns the fields for best access performance. The alignment
|
||||||
is compatible with the way the C compiler does it. For consistency
|
is compatible with the way the C compiler does it.
|
||||||
with ``object`` declarations, tuples in a ``type`` section can also be defined
|
|
||||||
with indentation instead of ``[]``:
|
For consistency with ``object`` declarations, tuples in a ``type`` section
|
||||||
|
can also be defined with indentation instead of ``[]``:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
|
@ -988,7 +989,7 @@ the ``of`` operator can be used to determine the object's type.
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
type
|
type
|
||||||
TPerson = 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
|
||||||
age: int # no * means that the field is hidden
|
age: int # no * means that the field is hidden
|
||||||
|
|
||||||
|
|
@ -1002,7 +1003,9 @@ the ``of`` operator can be used to determine the object's type.
|
||||||
|
|
||||||
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
|
||||||
never *equivalent*.
|
never *equivalent*. Objects that have no ancestor are implicitely ``final``
|
||||||
|
and thus have no hidden type field. One can use the ``inheritable`` pragma to
|
||||||
|
introduce new object roots apart from ``system.TObject``.
|
||||||
|
|
||||||
|
|
||||||
Object variants
|
Object variants
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,11 @@ section.
|
||||||
|
|
||||||
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
||||||
currently not supported. If an object type has no suitable ancestor, ``TObject``
|
currently not supported. If an object type has no suitable ancestor, ``TObject``
|
||||||
can be used as its ancestor, but this is only a convention.
|
can be used as its ancestor, but this is only a convention. Objects that have
|
||||||
|
no ancestor are implicitely ``final``. You can use the ``inheritable`` pragma
|
||||||
|
to introduce new object roots apart from ``system.TObject``. (This is used
|
||||||
|
in the GTK wrapper for instance.)
|
||||||
|
|
||||||
|
|
||||||
**Note**: Composition (*has-a* relation) is often preferable to inheritance
|
**Note**: Composition (*has-a* relation) is often preferable to inheritance
|
||||||
(*is-a* relation) for simple code reuse. Since objects are value types in
|
(*is-a* relation) for simple code reuse. Since objects are value types in
|
||||||
|
|
|
||||||
|
|
@ -1057,7 +1057,7 @@ type
|
||||||
charset: set[char] ## if kind == tkCharSet
|
charset: set[char] ## if kind == tkCharSet
|
||||||
index: int ## if kind == tkBackref
|
index: int ## if kind == tkBackref
|
||||||
|
|
||||||
TPegLexer = object ## the lexer object.
|
TPegLexer {.inheritable.} = object ## the lexer object.
|
||||||
bufpos: int ## the current position within the buffer
|
bufpos: int ## the current position within the buffer
|
||||||
buf: cstring ## the buffer itself
|
buf: cstring ## the buffer itself
|
||||||
LineNumber: int ## the current line number
|
LineNumber: int ## the current line number
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ type
|
||||||
Features: seq[Feature] # Read-Only
|
Features: seq[Feature] # Read-Only
|
||||||
|
|
||||||
PNode* = ref Node
|
PNode* = ref Node
|
||||||
Node = object
|
Node = object of TObject
|
||||||
attributes*: seq[PAttr]
|
attributes*: seq[PAttr]
|
||||||
childNodes*: seq[PNode]
|
childNodes*: seq[PNode]
|
||||||
FLocalName: string # Read-only
|
FLocalName: string # Read-only
|
||||||
|
|
|
||||||
|
|
@ -171,9 +171,12 @@ proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} =
|
||||||
proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} =
|
proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} =
|
||||||
result = value >= s.a and value <= s.b
|
result = value >= s.a and value <= s.b
|
||||||
|
|
||||||
|
when not defined(niminheritable):
|
||||||
|
{.pragma: inheritable.}
|
||||||
|
|
||||||
when not defined(EcmaScript) and not defined(NimrodVM):
|
when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
type
|
type
|
||||||
TGenericSeq {.compilerproc, pure.} = object
|
TGenericSeq {.compilerproc, pure, inheritable.} = object
|
||||||
len, reserved: int
|
len, reserved: int
|
||||||
PGenericSeq {.exportc.} = ptr TGenericSeq
|
PGenericSeq {.exportc.} = ptr TGenericSeq
|
||||||
# len and space without counting the terminating zero:
|
# len and space without counting the terminating zero:
|
||||||
|
|
@ -197,7 +200,7 @@ type
|
||||||
## is an int type ranging from one to the maximum value
|
## is an int type ranging from one to the maximum value
|
||||||
## of an int. This type is often useful for documentation and debugging.
|
## of an int. This type is often useful for documentation and debugging.
|
||||||
|
|
||||||
TObject* {.exportc: "TNimObject".} =
|
TObject* {.exportc: "TNimObject", inheritable.} =
|
||||||
object ## the root of Nimrod's object hierarchy. Objects should
|
object ## the root of Nimrod's object hierarchy. Objects should
|
||||||
## inherit from TObject or one of its descendants. However,
|
## inherit from TObject or one of its descendants. However,
|
||||||
## objects that have no ancestor are allowed.
|
## objects that have no ancestor are allowed.
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ type
|
||||||
PChunk = ptr TBaseChunk
|
PChunk = ptr TBaseChunk
|
||||||
PBigChunk = ptr TBigChunk
|
PBigChunk = ptr TBigChunk
|
||||||
PSmallChunk = ptr TSmallChunk
|
PSmallChunk = ptr TSmallChunk
|
||||||
TBaseChunk {.pure.} = object
|
TBaseChunk {.pure, inheritable.} = object
|
||||||
prevSize: int # size of previous chunk; for coalescing
|
prevSize: int # size of previous chunk; for coalescing
|
||||||
size: int # if < PageSize it is a small chunk
|
size: int # if < PageSize it is a small chunk
|
||||||
used: bool # later will be optimized into prevSize...
|
used: bool # later will be optimized into prevSize...
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ type
|
||||||
g_class*: PGTypeClass
|
g_class*: PGTypeClass
|
||||||
|
|
||||||
PGTypeInterface* = ptr TGTypeInterface
|
PGTypeInterface* = ptr TGTypeInterface
|
||||||
TGTypeInterface*{.pure.} = object
|
TGTypeInterface*{.pure, inheritable.} = object
|
||||||
g_type*: GType
|
g_type*: GType
|
||||||
g_instance_type*: GType
|
g_instance_type*: GType
|
||||||
|
|
||||||
|
|
@ -993,7 +993,7 @@ proc plugin_complete_interface_info*(plugin: PGTypePlugin,
|
||||||
dynlib: gliblib, importc: "g_type_plugin_complete_interface_info".}
|
dynlib: gliblib, importc: "g_type_plugin_complete_interface_info".}
|
||||||
type
|
type
|
||||||
PGObject* = ptr TGObject
|
PGObject* = ptr TGObject
|
||||||
TGObject*{.pure.} = object
|
TGObject*{.pure, inheritable.} = object
|
||||||
g_type_instance*: TGTypeInstance
|
g_type_instance*: TGTypeInstance
|
||||||
ref_count*: guint
|
ref_count*: guint
|
||||||
qdata*: PGData
|
qdata*: PGData
|
||||||
|
|
@ -1006,7 +1006,7 @@ type
|
||||||
TGWeakNotify* = proc (data: gpointer, where_the_object_was: PGObject){.cdecl.}
|
TGWeakNotify* = proc (data: gpointer, where_the_object_was: PGObject){.cdecl.}
|
||||||
PGObjectConstructParam* = ptr TGObjectConstructParam
|
PGObjectConstructParam* = ptr TGObjectConstructParam
|
||||||
PGObjectClass* = ptr TGObjectClass
|
PGObjectClass* = ptr TGObjectClass
|
||||||
TGObjectClass*{.pure.} = object
|
TGObjectClass*{.pure, inheritable.} = object
|
||||||
g_type_class*: TGTypeClass
|
g_type_class*: TGTypeClass
|
||||||
construct_properties*: PGSList
|
construct_properties*: PGSList
|
||||||
constructor*: proc (theType: GType, n_construct_properties: guint,
|
constructor*: proc (theType: GType, n_construct_properties: guint,
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ type
|
||||||
float*: float64
|
float*: float64
|
||||||
imag*: float64
|
imag*: float64
|
||||||
|
|
||||||
TPyObject*{.pure.} = object
|
TPyObject*{.pure, inheritable.} = object
|
||||||
ob_refcnt*: int
|
ob_refcnt*: int
|
||||||
ob_type*: PPyTypeObject
|
ob_type*: PPyTypeObject
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1052,7 +1052,7 @@ type
|
||||||
charset: set[char] ## if kind == tkCharSet
|
charset: set[char] ## if kind == tkCharSet
|
||||||
index: int ## if kind == tkBackref
|
index: int ## if kind == tkBackref
|
||||||
|
|
||||||
TPegLexer = object ## the lexer object.
|
TPegLexer {.inheritable.} = object ## the lexer object.
|
||||||
bufpos: int ## the current position within the buffer
|
bufpos: int ## the current position within the buffer
|
||||||
buf: cstring ## the buffer itself
|
buf: cstring ## the buffer itself
|
||||||
LineNumber: int ## the current line number
|
LineNumber: int ## the current line number
|
||||||
|
|
|
||||||
5
todo.txt
5
todo.txt
|
|
@ -1,13 +1,14 @@
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- ``final`` should be the default for objects
|
|
||||||
- implement "closure tuple consists of a single 'ref'" optimization
|
- implement "closure tuple consists of a single 'ref'" optimization
|
||||||
- implement for loop transformation for first class iterators
|
- implement for loop transformation for first class iterators
|
||||||
|
|
||||||
- implicit deref for parameter matching
|
- implicit deref for parameter matching
|
||||||
- optimize genericAssign in the code generator
|
- optimize genericAssign in the code generator
|
||||||
- the lookup rules for generics really are too permissive
|
- the lookup rules for generics really are too permissive; global scope only
|
||||||
|
doesn't fly with closures though; for a start add a warning when processing
|
||||||
|
generic code
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
- test evals.nim with closures
|
- test evals.nim with closures
|
||||||
- what about macros with closures?
|
- what about macros with closures?
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,9 @@ Changes affecting backwards compatibility
|
||||||
- The Nimrod type system now distinguishes ``openarray`` from ``varargs``.
|
- The Nimrod type system now distinguishes ``openarray`` from ``varargs``.
|
||||||
- Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old
|
- Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old
|
||||||
behaviour.
|
behaviour.
|
||||||
|
- Objects that have no ancestor are now implicitely ``final``. Use
|
||||||
|
the ``inheritable`` pragma to introduce new object roots apart
|
||||||
|
from ``TObject``.
|
||||||
|
|
||||||
|
|
||||||
Compiler Additions
|
Compiler Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue