implemented procCall builtin

This commit is contained in:
Araq 2014-11-28 02:43:41 +01:00
commit 105a0616a9
11 changed files with 63 additions and 52 deletions

View file

@ -566,8 +566,8 @@ type
mBool, mChar, mString, mCstring, mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mIsMainModule, mCompileDate, mCompileTime, mProcCall,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf, mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg, mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,

View file

@ -12,10 +12,6 @@
const const
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets? MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
VersionMajor* = 0 VersionAsString* = system.NimVersion
VersionMinor* = 10
VersionPatch* = 1
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1215" # modify this if the rod-format changes! RodFileVersion* = "1215" # modify this if the rod-format changes!

View file

@ -1649,6 +1649,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: else:
result.typ = result[1].typ result.typ = result[1].typ
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
of mProcCall:
result = setMs(n, s)
result.sons[1] = semExpr(c, n.sons[1])
result.typ = n[1].typ
else: result = semDirectOp(c, n, flags) else: result = semDirectOp(c, n, flags)
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =

View file

@ -613,10 +613,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
of mCompileTime: result = newStrNodeT(times.getClockStr(), n) of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
of mNimrodVersion: result = newStrNodeT(VersionAsString, n)
of mNimrodMajor: result = newIntNodeT(VersionMajor, n)
of mNimrodMinor: result = newIntNodeT(VersionMinor, n)
of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n) of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n) of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)

View file

@ -130,4 +130,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mShallowCopy: result = semShallowCopy(c, n, flags) of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n) of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n) of mLocals: result = semLocals(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
else: result = n else: result = n

View file

@ -582,7 +582,7 @@ proc getMergeOp(n: PNode): PSym =
else: discard else: discard
proc flattenTreeAux(d, a: PNode, op: PSym) = proc flattenTreeAux(d, a: PNode, op: PSym) =
var op2 = getMergeOp(a) let op2 = getMergeOp(a)
if op2 != nil and if op2 != nil and
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic): (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op) for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
@ -590,7 +590,7 @@ proc flattenTreeAux(d, a: PNode, op: PSym) =
addSon(d, copyTree(a)) addSon(d, copyTree(a))
proc flattenTree(root: PNode): PNode = proc flattenTree(root: PNode): PNode =
var op = getMergeOp(root) let op = getMergeOp(root)
if op != nil: if op != nil:
result = copyNode(root) result = copyNode(root)
addSon(result, copyTree(root.sons[0])) addSon(result, copyTree(root.sons[0]))
@ -600,8 +600,9 @@ proc flattenTree(root: PNode): PNode =
proc transformCall(c: PTransf, n: PNode): PTransNode = proc transformCall(c: PTransf, n: PNode): PTransNode =
var n = flattenTree(n) var n = flattenTree(n)
var op = getMergeOp(n) let op = getMergeOp(n)
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3): let magic = getMagic(n)
if op != nil and op.magic != mNone and n.len >= 3:
result = newTransNode(nkCall, n, 0) result = newTransNode(nkCall, n, 0)
add(result, transform(c, n.sons[0])) add(result, transform(c, n.sons[0]))
var j = 1 var j = 1
@ -616,9 +617,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
inc(j) inc(j)
add(result, a.PTransNode) add(result, a.PTransNode)
if len(result) == 2: result = result[1] if len(result) == 2: result = result[1]
elif getMagic(n) == mNBindSym: elif magic == mNBindSym:
# for bindSym(myconst) we MUST NOT perform constant folding: # for bindSym(myconst) we MUST NOT perform constant folding:
result = n.PTransNode result = n.PTransNode
elif magic == mProcCall:
# but do not change to its dispatcher:
result = transformSons(c, n[1])
else: else:
let s = transformSons(c, n).PNode let s = transformSons(c, n).PNode
# bugfix: check after 'transformSons' if it's still a method call: # bugfix: check after 'transformSons' if it's still a method call:

View file

@ -16,7 +16,7 @@ the best match for the arguments. Example:
.. code-block:: nim .. code-block:: nim
proc toLower(c: Char): Char = # toLower for characters proc toLower(c: char): char = # toLower for characters
if c in {'A'..'Z'}: if c in {'A'..'Z'}:
result = chr(ord(c) + (ord('a') - ord('A'))) result = chr(ord(c) + (ord('a') - ord('A')))
else: else:
@ -237,7 +237,7 @@ The following builtin procs cannot be overloaded for reasons of implementation
simplicity (they require specialized semantic checking):: simplicity (they require specialized semantic checking)::
declared, defined, definedInScope, compiles, low, high, sizeOf, declared, defined, definedInScope, compiles, low, high, sizeOf,
is, of, shallowCopy, getAst, astToStr, spawn is, of, shallowCopy, getAst, astToStr, spawn, procCall
Thus they act more like keywords than like ordinary identifiers; unlike a Thus they act more like keywords than like ordinary identifiers; unlike a
keyword however, a redefinition may `shadow`:idx: the definition in keyword however, a redefinition may `shadow`:idx: the definition in

View file

@ -1016,22 +1016,6 @@ const
## is the time of compilation as a string of the form ## is the time of compilation as a string of the form
## ``HH:MM:SS``. This works thanks to compiler magic. ## ``HH:MM:SS``. This works thanks to compiler magic.
NimVersion* {.magic: "NimrodVersion"}: string = "0.0.0"
## is the version of Nim as a string.
## This works thanks to compiler magic.
NimMajor* {.magic: "NimrodMajor"}: int = 0
## is the major number of Nim's version.
## This works thanks to compiler magic.
NimMinor* {.magic: "NimrodMinor"}: int = 0
## is the minor number of Nim's version.
## This works thanks to compiler magic.
NimPatch* {.magic: "NimrodPatch"}: int = 0
## is the patch number of Nim's version.
## This works thanks to compiler magic.
cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian
## is the endianness of the target CPU. This is a valuable piece of ## is the endianness of the target CPU. This is a valuable piece of
## information for low-level code only. This works thanks to compiler ## information for low-level code only. This works thanks to compiler
@ -1048,9 +1032,6 @@ const
seqShallowFlag = low(int) seqShallowFlag = low(int)
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
proc compileOption*(option: string): bool {. proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.} magic: "CompileOption", noSideEffect.}
## can be used to determine an on|off compile-time option. Example: ## can be used to determine an on|off compile-time option. Example:
@ -1529,6 +1510,20 @@ const
## that you cannot compare a floating point value to this value ## that you cannot compare a floating point value to this value
## and expect a reasonable result - use the `classify` procedure ## and expect a reasonable result - use the `classify` procedure
## in the module ``math`` for checking for NaN. ## in the module ``math`` for checking for NaN.
NimMajor*: int = 0
## is the major number of Nim's version.
NimMinor*: int = 10
## is the minor number of Nim's version.
NimPatch*: int = 1
## is the patch number of Nim's version.
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
## is the version of Nim as a string.
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
# GC interface: # GC interface:
@ -3104,7 +3099,7 @@ proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
## generates a tuple constructor expression listing all the local variables ## generates a tuple constructor expression listing all the local variables
## in the current scope. This is quite fast as it does not rely ## in the current scope. This is quite fast as it does not rely
## on any debug or runtime information. Note that in constrast to what ## on any debug or runtime information. Note that in constrast to what
## the official signature says, the return type is not ``TObject`` but a ## the official signature says, the return type is not ``RootObj`` but a
## tuple of a structure that depends on the current scope. Example: ## tuple of a structure that depends on the current scope. Example:
## ##
## .. code-block:: nim ## .. code-block:: nim
@ -3132,4 +3127,13 @@ when hostOS != "standalone" and not defined(NimrodVM) and not defined(JS):
include "system/deepcopy" include "system/deepcopy"
proc procCall*(x: expr) {.magic: "ProcCall".} =
## special magic to prohibit dynamic binding for `method`:idx: calls.
## This is similar to `super`:idx: in ordinary OO languages.
##
## .. code-block:: nim
## # 'someMethod' will be resolved fully statically:
## procCall someMethod(a, b)
discard
{.pop.} #{.push warning[GcMem]: off.} {.pop.} #{.push warning[GcMem]: off.}

View file

@ -1,6 +1,9 @@
discard """ discard """
file: "tmultim2.nim" file: "tmultim2.nim"
output: "collide: unit, thing collide: unit, thing collide: thing, unit" output: '''collide: unit, thing
collide: unit, thing
collide: thing, unit
collide: thing, thing'''
""" """
# Test multi methods # Test multi methods
@ -12,25 +15,25 @@ type
a, b: int a, b: int
method collide(a, b: TThing) {.inline.} = method collide(a, b: TThing) {.inline.} =
quit "to override!" echo "collide: thing, thing"
method collide(a: TThing, b: TUnit) {.inline.} = method collide(a: TThing, b: TUnit) {.inline.} =
write stdout, "collide: thing, unit " echo "collide: thing, unit"
method collide(a: TUnit, b: TThing) {.inline.} = method collide(a: TUnit, b: TThing) {.inline.} =
write stdout, "collide: unit, thing " echo "collide: unit, thing"
proc test(a, b: TThing) {.inline.} = proc test(a, b: TThing) {.inline.} =
collide(a, b) collide(a, b)
proc staticCollide(a, b: TThing) {.inline.} =
procCall collide(a, b)
var var
a: TThing a: TThing
b, c: TUnit b, c: TUnit
collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing! collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing!
test(b, c) test(b, c)
collide(a, b) collide(a, b)
#OUT collide: unit, thing collide: unit, thing collide: thing, unit staticCollide(a, b)

View file

@ -2,7 +2,6 @@ version 0.10
============ ============
- make nimble part of the distribution - make nimble part of the distribution
- implement 'procCall'
- split idetools into separate tool - split idetools into separate tool
- split docgen into separate tool - split docgen into separate tool

View file

@ -36,6 +36,8 @@ News
lock levels and object field ``guards``. lock levels and object field ``guards``.
- The ``parallel`` statement has been implemented. - The ``parallel`` statement has been implemented.
- ``deepCopy`` has been added to the language. - ``deepCopy`` has been added to the language.
- The builtin ``procCall`` can be used to get ``super``-like functionality
for multi methods.
Compiler Additions Compiler Additions