# # # The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements code generation for multi methods. import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, sempass2, strutils, modulegraphs, lineinfos proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) var source = skipTypes(n.typ, abstractPtrs) if (source.kind == tyObject) and (dest.kind == tyObject): var diff = inheritanceDiff(dest, source) if diff == high(int): # no subtype relation, nothing to do result = n elif diff < 0: result = newNodeIT(nkObjUpConv, n.info, d) addSon(result, n) if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed") elif diff > 0: result = newNodeIT(nkObjDownConv, n.info, d) addSon(result, n) if not downcast: internalError(conf, n.info, "cgmeth.genConv: no downcast allowed") else: result = n else: result = n proc getDispatcher*(s: PSym): PSym = ## can return nil if is has no dispatcher. let dispn = lastSon(s.ast) if dispn.kind == nkSym: let disp = dispn.sym if sfDispatcher in disp.flags: result = disp proc methodCall*(n: PNode; conf: ConfigRef): PNode = result = n # replace ordinary method by dispatcher method: let disp = getDispatcher(result.sons[0].sym) if disp != nil: result.sons[0].sym = disp # change the arguments to up/downcasts to fit the dispatcher's parameters: for i in countup(1, sonsLen(result)-1): result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf) else: localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher") type MethodResult = enum No, Invalid, Yes proc sameMethodBucket(a, b: PSym): MethodResult = if a.name.id != b.name.id: return if sonsLen(a.typ) != sonsLen(b.typ): return for i in countup(1, sonsLen(a.typ) - 1): var aa = a.typ.sons[i] var bb = b.typ.sons[i] while true: aa = skipTypes(aa, {tyGenericInst, tyAlias}) bb = skipTypes(bb, {tyGenericInst, tyAlias}) if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}: aa = aa.lastSon bb = bb.lastSon else: break if sameType(aa, bb): if aa.kind == tyObject and result != Invalid: result = Yes elif aa.kind == tyObject and bb.kind == tyObject: let diff = inheritanceDiff(bb, aa) if diff < 0: if result != Invalid: result = Yes else: return No elif diff != high(int): result = Invalid else: return No else: return No if result == Yes: # check for return type: if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): if b.typ.sons[0] != nil and b.typ.sons[0].kind == tyExpr: # infer 'auto' from the base to make it consistent: b.typ.sons[0] = a.typ.sons[0] else: return No proc attachDispatcher(s: PSym, dispatcher: PNode) = var L = s.ast.len-1 var x = s.ast.sons[L] if x.kind == nkSym and sfDispatcher in x.sym.flags: # we've added a dispatcher already, so overwrite it s.ast.sons[L] = dispatcher else: s.ast.add(dispatcher) proc createDispatcher(s: PSym): PSym = var disp = copySym(s) incl(disp.flags, sfDispatcher) excl(disp.flags, sfExported) disp.typ = copyType(disp.typ, disp.typ.owner, false) # we can't inline the dispatcher itself (for now): if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault disp.ast = copyTree(s.ast) disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info) disp.loc.r = nil if s.typ.sons[0] != nil: if disp.ast.sonsLen > resultPos: disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will # be updated in fixupDispatcher(). disp.ast.addSon(newNodeI(nkEmpty, s.info)) attachDispatcher(s, newSymNode(disp)) #
# This is test program for the osproc module.

import os

echo getCurrentDir()

for i in 1..paramCount():
  echo paramStr(i)
spatcher(g, g.methods[bucket].methods, relevantCols)))