summary refs log tree commit diff stats
path: root/compiler/magicsys.nim
blob: 6a9d690823a15d3a90b7a660432366f273b0f849 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
generated by cgit-pink 1.4.1-2-gfad0 (git 2.36.2.497.gbbea4dcf42) at 2025-07-07 05:48:41 +0000
 


background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#
#
#           The Nim Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# Built-in types and compilerprocs are registered here.

import
  ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread

var systemModule*: PSym

var
  gSysTypes: array[TTypeKind, PType]
  compilerprocs: TStrTable
  exposed: TStrTable

proc nilOrSysInt*: PType = gSysTypes[tyInt]

proc registerSysType*(t: PType) =
  if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t

proc newSysType(kind: TTypeKind, size: int): PType =
  result = newType(kind, systemModule)
  result.size = size
  result.align = size.int16

proc getSysSym*(name: string): PSym =
  result = strTableGet(systemModule.tab, getIdent(name))
  if result == nil:
    rawMessage(errSystemNeeds, name)
    result = newSym(skError, getIdent(name), systemModule, systemModule.info)
    result.typ = newType(tyError, systemModule)
  if result.kind == skStub: loadStub(result)
  if result.kind == skAlias: result = result.owner

proc createMagic*(name: string, m: TMagic): PSym =
  result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
  result.magic = m

let
  opNot* = createMagic("not", mNot)
  opContains* = createMagic("contains", mInSet)

proc getSysMagic*(name: string, m: TMagic): PSym =
  var ti: TIdentIter
  let id = getIdent(name)
  var r = initIdentIter(ti, systemModule.tab, id)
  while r != nil:
    if r.kind == skStub: loadStub(r)
    if r.magic == m:
      # prefer the tyInt variant:
      if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
      result = r
    r = nextIdentIter(ti, systemModule.tab)
  if result != nil: return result
  rawMessage(errSystemNeeds, name)
  result = newSym(skError, id, systemModule, systemModule.info)
  result.typ = newType(tyError, systemModule)

proc sysTypeFromName*(name: string): PType =
  result = getSysSym(name).typ

proc getSysType*(kind: TTypeKind): PType =
  result = gSysTypes[kind]
  if result == nil:
    case kind
    of tyInt: result = sysTypeFromName("int")
    of tyInt8: result = sysTypeFromName("int8")
    of tyInt16: result = sysTypeFromName("int16")
    of tyInt32: result = sysTypeFromName("int32")
    of tyInt64: result = sysTypeFromName("int64")
    of tyUInt: result = sysTypeFromName("uint")
    of tyUInt8: result = sysTypeFromName("uint8")
    of tyUInt16: result = sysTypeFromName("uint16")
    of tyUInt32: result = sysTypeFromName("uint32")
    of tyUInt64: result = sysTypeFromName("uint64")
    of tyFloat: result = sysTypeFromName("float")
    of tyFloat32: result = sysTypeFromName("float32")
    of tyFloat64: return sysTypeFromName("float64")
    of tyFloat128: result = sysTypeFromName("float128")
    of tyBool: result = sysTypeFromName("bool")
    of tyChar: result = sysTypeFromName("char")
    of tyString: result = sysTypeFromName("string")
    of tyCString: result = sysTypeFromName("cstring")
    of tyPointer: result = sysTypeFromName("pointer")
    of tyNil: result = newSysType(tyNil, ptrSize)
    else: internalError("request for typekind: " & $kind)
    gSysTypes[kind] = result
  if result.kind != kind:
    internalError("wanted: " & $kind & " got: " & $result.kind)
  if result == nil: internalError("type not found: " & $kind)

var
  intTypeCache: array[-5..64, PType]

proc resetSysTypes* =
  systemModule = nil
  initStrTable(compilerprocs)
  initStrTable(exposed)
  for i in low(gSysTypes)..high(gSysTypes):
    gSysTypes[i] = nil

  for i in low(intTypeCache)..high(intTypeCache):
    intTypeCache[i] = nil

proc getIntLitType*(literal: PNode): PType =
  # we cache some common integer literal types for performance:
  let value = literal.intVal
  if value >= low(intTypeCache) and value <= high(intTypeCache):
    result = intTypeCache[value.int]
    if result == nil:
      let ti = getSysType(tyInt)
      result = copyType(ti, ti.owner, false)
      result.n = literal
      intTypeCache[value.int] = result
  else:
    let ti = getSysType(tyInt)
    result = copyType(ti, ti.owner, false)
    result.n = literal

proc getFloatLitType*(literal: PNode): PType =
  # for now we do not cache these:
  result = newSysType(tyFloat, size=8)
  result.n = literal

proc skipIntLit*(t: PType): PType {.inline.} =
  if t.n != nil:
    if t.kind in {tyInt, tyFloat}:
      return getSysType(t.kind)
  result = t

proc addSonSkipIntLit*(father, son: PType) =
  if isNil(father.sons): father.sons = @[]
  let s = son.skipIntLit
  add(father.sons, s)
  propagateToOwner(father, s)

proc setIntLitType*(result: PNode) =
  let i = result.intVal
  case platform.intSize
  of 8: result.typ = getIntLitType(result)
  of 4:
    if i >= low(int32) and i <= high(int32):
      result.typ = getIntLitType(result)
    else:
      result.typ = getSysType(tyInt64)
  of 2:
    if i >= low(int16) and i <= high(int16):
      result.typ = getIntLitType(result)
    elif i >= low(int32) and i <= high(int32):
      result.typ = getSysType(tyInt32)
    else:
      result.typ = getSysType(tyInt64)
  of 1:
    # 8 bit CPUs are insane ...
    if i >= low(int8) and i <= high(int8):
      result.typ = getIntLitType(result)
    elif i >= low(int16) and i <= high(int16):
      result.typ = getSysType(tyInt16)
    elif i >= low(int32) and i <= high(int32):
      result.typ = getSysType(tyInt32)
    else:
      result.typ = getSysType(tyInt64)
  else: internalError(result.info, "invalid int size")

proc getCompilerProc*(name: string): PSym =
  let ident = getIdent(name)
  result = strTableGet(compilerprocs, ident)
  if result == nil:
    result = strTableGet(rodCompilerprocs, ident)
    if result != nil:
      strTableAdd(compilerprocs, result)
      if result.kind == skStub: loadStub(result)
      if result.kind == skAlias: result = result.owner

proc registerCompilerProc*(s: PSym) =
  strTableAdd(compilerprocs, s)

proc registerNimScriptSymbol*(s: PSym) =
  # Nimscript symbols must be al unique:
  let conflict = strTableGet(exposed, s.name)
  if conflict == nil:
    strTableAdd(exposed, s)
  else:
    localError(s.info, "symbol conflicts with other .exportNims symbol at: " &
      $conflict.info)

proc getNimScriptSymbol*(name: string): PSym =
  strTableGet(exposed, getIdent(name))

proc resetNimScriptSymbols*() = initStrTable(exposed)

initStrTable(compilerprocs)
initStrTable(exposed)