<commit_before>#
#
#           The Nim Compiler
#        (c) Copyright 2016 <NAME>
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# included from cgen.nim

# ------------------------- Name Mangling --------------------------------

import sighashes

proc isKeyword(w: PIdent): bool =
  # Nim and C++ share some keywords
  # it's more efficient to test the whole Nim keywords range
  case w.id
  of ccgKeywordsLow..ccgKeywordsHigh,
     nimKeywordsLow..nimKeywordsHigh,
     ord(wInline): return true
  else: return false

proc mangleField(name: PIdent): string =
  result = mangle(name.s)
  if isKeyword(name):
    result[0] = result[0].toUpperAscii
    # Mangling makes everything lowercase,
    # but some identifiers are C keywords

when false:
  proc hashOwner(s: PSym): SigHash =
    var m = s
    while m.kind != skModule: m = m.owner
    let p = m.owner
    assert p.kind == skPackage
    result = gDebugInfo.register(p.name.s, m.name.s)

proc idOrSig(m: BModule; s: PSym): Rope =
  if s.kind in routineKinds and s.typ != nil:
    # signatures for exported routines are reliable enough to
    # produce a unique name and this means produced C++ is more stable wrt
    # Nim changes:
    let sig = hashProc(s)
    result = rope($sig)
    #let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
    let counter = m.sigConflicts.getOrDefault(sig)
    #if sigs == "_jckmNePK3i2MFnWwZlp6Lg" and s.name.s == "contains":
    #  echo "counter ", counter, " ", s.id
    if counter != 0:
      result.add "_" & rope(counter+1)
    # this minor hack is necessary to make tests/collections/thashes compile.
    # The inlined hash function's original module is ambiguous so we end up
    # generating duplicate names otherwise:
    if s.typ.callConv == ccInline:
      result.add rope(m.module.name.s)
    m.sigConflicts.inc(sig)
  else:
    let sig = hashNonProc(s)
    result = rope($sig)
    let counter = m.sigConflicts.getOrDefault(sig)
    if counter != 0:
      result.add "_" & rope(counter+1)
    m.sigConflicts.inc(sig)

proc mangleName(m: BModule; s: PSym): Rope =
  result = s.loc.r
  if result == nil:
    let keepOrigName = s.kind in skLocalVars - {skForVar} and
      {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
      not isKeyword(s.name)
    # Even with all these inefficient checks, the bootstrap
    # time is actually improved. This is probably because so many
    # rope concatenations are now eliminated.
    #
    # sfFromGeneric is needed in order to avoid multiple
    # definitions of certain variables generated in transf with
    # names such as:
    # `r`, `res`
    # I need to study where these come from.
    #
    # about sfShadowed:
    # consider the following Nim code:
    #   var x = 10
    #   block:
    #     var x = something(x)
    # The generated C code will be:
    #   NI x;
    #   x = 10;
    #   {
    #     NI x;
    #     x = something(x); // Oops, x is already shadowed here
    #   }
    # Right now, we work-around by not keeping the original name
    # of the shadowed variable, but we can do better - we can
    # create an alternative reference to it in the outer scope and
    # use that in the inner scope.
    #
    # about isCKeyword:
    # Nim variable names can be C keywords.
    # We need to avoid such names in the generated code.
    #
    # about sfGlobal:
    # This seems to be harder - a top level extern variable from
    # another modules can have the same name as a local one.
    # Maybe we should just implement sfShadowed for them too.
    #
    # about skForVar:
    # These are not properly scoped now - we need to add blocks
    # around for loops in transf
    result = s.name.s.mangle.rope
    if keepOrigName:
      result.add "0"
    else:
      add(result, m.idOrSig(s))
    s.loc.r = result

proc typeName(typ: PType): Rope =
  result = if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
             typ.sym.name.s.mangle.rope
           else:
             ~"TY"

const
  irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
                          tyDistinct, tyRange, tyStatic, tyAlias}

proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
  var typ = typ
  while true:
    if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
      return typ.sym.loc.r

    if typ.kind in irrelevantForBackend:
      typ = typ.lastSon
    else:
      break
  if typ.loc.r == nil:
    typ.loc.r = typ.typeName & $sig
  else:
    when defined(debugSigHashes):
      # check consistency:
      assert($typ.loc.r == $(typ.typeName & $sig))
  result = typ.loc.r
  if result == nil: internalError("getTypeName: " & $typ.kind)

proc mapSetType(typ: PType): TCTypeKind =
  case int(getSize(typ))
  of 1: result = ctInt8
  of 2: result = ctInt16
  of 4: result = ctInt32
  of 8: result = ctInt64
  else: result = ctArray

proc mapType(typ: PType): TCTypeKind =
  ## Maps a Nim type to a C type
  case typ.kind
  of tyNone, tyStmt: result = ctVoid
  of tyBool: result = ctBool
  of tyChar: result = ctChar
  of tySet: result = mapSetType(typ)
  of tyOpenArray, tyArray, tyVarargs: result = ctArray
  of tyObject, tyTuple: result = ctStruct
  of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
     tyTypeDesc, tyAlias:<commit_msg>make tsets test green again<commit_after>#
#
#           The Nim Compiler
#        (c) Copyright 2016 <NAME>
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# included from cgen.nim

# ------------------------- Name Mangling --------------------------------

import sighashes

proc isKeyword(w: PIdent): bool =
  # Nim and C++ share some keywords
  # it's more efficient to test the whole Nim keywords range
  case w.id
  of ccgKeywordsLow..ccgKeywordsHigh,
     nimKeywordsLow..nimKeywordsHigh,
     ord(wInline): return true
  else: return false

proc mangleField(name: PIdent): string =
  result = mangle(name.s)
  if isKeyword(name):
    result[0] = result[0].toUpperAscii
    # Mangling makes everything lowercase,
    # but some identifiers are C keywords

when false:
  proc hashOwner(s: PSym): SigHash =
    var m = s
    while m.kind != skModule: m = m.owner
    let p = m.owner
    assert p.kind == skPackage
    result = gDebugInfo.register(p.name.s, m.name.s)

proc idOrSig(m: BModule; s: PSym): Rope =
  if s.kind in routineKinds and s.typ != nil:
    # signatures for exported routines are reliable enough to
    # produce a unique name and this means produced C++ is more stable wrt
    # Nim changes:
    let sig = hashProc(s)
    result = rope($sig)
    #let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
    let counter = m.sigConflicts.getOrDefault(sig)
    #if sigs == "_jckmNePK3i2MFnWwZlp6Lg" and s.name.s == "contains":
    #  echo "counter ", counter, " ", s.id
    if counter != 0:
      result.add "_" & rope(counter+1)
    # this minor hack is necessary to make tests/collections/thashes compile.
    # The inlined hash function's original module is ambiguous so we end up
    # generating duplicate names otherwise:
    if s.typ.callConv == ccInline:
      result.add rope(m.module.name.s)
    m.sigConflicts.inc(sig)
  else:
    let sig = hashNonProc(s)
    result = rope($sig)
    let counter = m.sigConflicts.getOrDefault(sig)
    if counter != 0:
      result.add "_" & rope(counter+1)
    m.sigConflicts.inc(sig)

proc mangleName(m: BModule; s: PSym): Rope =
  result = s.loc.r
  if result == nil:
    let keepOrigName = s.kind in skLocalVars - {skForVar} and
      {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
      not isKeyword(s.name)
    # Even with all these inefficient checks, the bootstrap
    # time is actually improved. This is probably because so many
    # rope concatenations are now eliminated.
    #
    # sfFromGeneric is needed in order to avoid multiple
    # definitions of certain variables generated in transf with
    # names such as:
    # `r`, `res`
    # I need to study where these come from.
    #
    # about sfShadowed:
    # consider the following Nim code:
    #   var x = 10
    #   block:
    #     var x = something(x)
    # The generated C code will be:
    #   NI x;
    #   x = 10;
    #   {
    #     NI x;
    #     x = something(x); // Oops, x is already shadowed here
    #   }
    # Right now, we work-around by not keeping the original name
    # of the shadowed variable, but we can do better - we can
    # create an alternative reference to it in the outer scope and
    # use that in the inner scope.
    #
    # about isCKeyword:
    # Nim variable names can be C keywords.
    # We need to avoid such names in the generated code.
    #
    # about sfGlobal:
    # This seems to be harder - a top level extern variable from
    # another modules can have the same name as a local one.
    # Maybe we should just implement sfShadowed for them too.
    #
    # about skForVar:
    # These are not properly scoped now - we need to add blocks
    # around for loops in transf
    result = s.name.s.mangle.rope
    if keepOrigName:
      result.add "0"
    else:
      add(result, m.idOrSig(s))
    s.loc.r = result

proc typeName(typ: PType): Rope =
  result = if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
             typ.sym.name.s.mangle.rope
           else:
             ~"TY"

const
  irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
                          tyDistinct, tyRange, tyStatic, tyAlias}

proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
  var t = typ
  while true:
    if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
      return t.sym.loc.r

    if t.kind in irrelevantForBackend:
      t = t.lastSon
    else:
      break
  let typ = if typ.kind == tyAlias: typ.lastSon else: typ
  if typ.loc.r == nil:
    typ.loc.r = typ.typeName & $sig
  else:
    when defined(debugSigHashes):
      # check consistency:
      assert($typ.loc.r == $(typ.typeName & $sig))
  result = typ.loc.r
  if result == nil: internalError("getTypeName: " & $typ.kind)

proc mapSetType(typ: PType): TCTypeKind =
  case int(getSize(typ))
  of 1: result = ctInt8
  of 2: result = ctInt16
  of 4: result = ctInt32
  of 8: result = ctInt64
  else: result = ctArray

proc mapType(typ: PType): TCTypeKind =
  ## Maps a Nim type to a C type
  case typ.kind
  of tyNone, tyStmt: result = ctVoid
  of tyBool: result = ctBool
  of tyChar: result = ctChar
  of tySet: result = mapSetType(typ)
  of tyOpenArray, tyArray, tyVarargs: result = ctArray
  of tyObject, tyTuple: result = ctStruct
  of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
     tyTypeDesc, tyAlias:
{'fraction_non_alphanumeric': 0.10601001669449082, 'fraction_numerical': 0.005379335930254127, 'mean_word_length': 2.588352745424293, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3909340', 'n_tokens_mistral': 3583, 'n_tokens_neox': 3497, 'n_words': 1207}