summary refs log tree commit diff stats
path: root/compiler/cmdlinehelper.nim
blob: 8bd07331404845929d07ef762201968cda1b874b (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
#
#
#           The Nim Compiler
#        (c) Copyright 2018 Nim contributors
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix

import
  options, idents, nimconf, scriptconfig, extccomp, commands, msgs,
  lineinfos, modulegraphs, condsyms, os, pathutils

type
  NimProg* = ref object
    suggestMode*: bool
    supportsStdinFile*: bool
    processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef)
    mainCommand*: proc(graph: ModuleGraph)

proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
  condsyms.initDefines(conf.symbols)
  defineSymbol conf.symbols, name

proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
  self.processCmdLine(passCmd1, "", conf)
  if self.supportsStdinFile and conf.projectName == "-":
    conf.projectName = "stdinfile"
    conf.projectFull = AbsoluteFile "stdinfile"
    conf.projectPath = AbsoluteDir getCurrentDir()
    conf.projectIsStdin = true
  elif conf.projectName != "":
    try:
      conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName)
    except OSError:
      conf.projectFull = AbsoluteFile conf.projectName
    let p = splitFile(conf.projectFull)
    let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir
    conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir)
    conf.projectName = p.name
  else:
    conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir())

proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
  loadConfigs(DefaultConfig, cache, conf) # load all config files
  if self.suggestMode:
    conf.command = "nimsuggest"

  proc runNimScriptIfExists(path: AbsoluteFile)=
    if fileExists(path):
      runNimScript(cache, path, freshDefines = false, conf)

  # Caution: make sure this stays in sync with `loadConfigs`
  if optSkipSystemConfigFile notin conf.globalOptions:
    runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims))

  if optSkipUserConfigFile notin conf.globalOptions:
    runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))

  if optSkipParentConfigFiles notin conf.globalOptions:
    for dir in parentDirs(conf.projectPath.string, fromRoot = true, inclusive = false):
      runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims)

  if optSkipProjConfigFile notin conf.globalOptions:
    runNimScriptIfExists(conf.projectPath / DefaultConfigNims)
  block:
    let scriptFile = conf.projectFull.changeFileExt("nims")
    if not self.suggestMode:
      runNimScriptIfExists(scriptFile)
      # 'nim foo.nims' means to just run the NimScript file and do nothing more:
      if fileExists(scriptFile) and scriptFile == conf.projectFull:
        return false
    else:
      if scriptFile != conf.projectFull:
        runNimScriptIfExists(scriptFile)
      else:
        # 'nimsuggest foo.nims' means to just auto-complete the NimScript file
        discard

  # now process command line arguments again, because some options in the
  # command line can overwite the config file's settings
  extccomp.initVars(conf)
  self.processCmdLine(passCmd2, "", conf)
  if conf.command == "":
    rawMessage(conf, errGenerated, "command missing")

  let graph = newModuleGraph(cache, conf)
  graph.suggestMode = self.suggestMode
  self.mainCommand(graph)
  return true
>*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, filter: TSymKinds): PNode {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} includedFiles*: TIntSet # used to detect recursive include files userPragmas*: TStrTable evalContext*: PEvalContext UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent # naming it multiple times generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile lastGenericIdx*: int # used for the generics stack proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s result.inst = inst proc filename*(c: PContext): string = # the module's filename return c.module.filename proc newContext*(module: PSym): PContext proc lastOptionEntry*(c: PContext): POptionEntry proc newOptionEntry*(): POptionEntry proc newLib*(kind: TLibKind): PLib proc addToLib*(lib: PLib, sym: PSym) proc makePtrType*(c: PContext, baseType: PType): PType proc makeVarType*(c: PContext, baseType: PType): PType proc newTypeS*(kind: TTypeKind, c: PContext): PType proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) # owner handling: proc getCurrOwner*(): PSym proc PushOwner*(owner: PSym) proc PopOwner*() # implementation var gOwners*: seq[PSym] = @[] proc getCurrOwner(): PSym = # owner stack (used for initializing the # owner field of syms) # the documentation comment always gets # assigned to the current owner # BUGFIX: global array is needed! result = gOwners[high(gOwners)] proc PushOwner(owner: PSym) = add(gOwners, owner) proc PopOwner() = var length = len(gOwners) if length > 0: setlen(gOwners, length - 1) else: InternalError("popOwner") proc lastOptionEntry(c: PContext): POptionEntry = result = POptionEntry(c.optionStack.tail) proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = if owner == nil: InternalError("owner is nil") return var x: PProcCon new(x) x.owner = owner x.next = c.p c.p = x proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc newOptionEntry(): POptionEntry = new(result) result.options = gOptions result.defaultCC = ccDefault result.dynlib = nil result.notes = gNotes proc newContext(module: PSym): PContext = new(result) result.AmbiguousSymbols = initIntset() initLinkedList(result.optionStack) initLinkedList(result.libs) append(result.optionStack, newOptionEntry()) result.module = module result.friendModule = module result.threadEntries = @[] result.converters = @[] result.patterns = @[] result.includedFiles = initIntSet() initStrTable(result.userPragmas) result.generics = @[] result.UnknownIdents = initIntSet() proc inclSym(sq: var TSymSeq, s: PSym) = var L = len(sq) for i in countup(0, L - 1): if sq[i].id == s.id: return setlen(sq, L + 1) sq[L] = s proc addConverter*(c: PContext, conv: PSym) = inclSym(c.converters, conv) proc addPattern*(c: PContext, p: PSym) = inclSym(c.patterns, p) proc newLib(kind: TLibKind): PLib = new(result) result.kind = kind #initObjectSet(result.syms) proc addToLib(lib: PLib, sym: PSym) = #ObjectSetIncl(lib.syms, sym); if sym.annex != nil: LocalError(sym.info, errInvalidPragma) sym.annex = lib proc makePtrType(c: PContext, baseType: PType): PType = result = newTypeS(tyPtr, c) addSonSkipIntLit(result, baseType.AssertNotNil) proc makeVarType(c: PContext, baseType: PType): PType = result = newTypeS(tyVar, c) addSonSkipIntLit(result, baseType.AssertNotNil) proc makeTypeDesc*(c: PContext, typ: PType): PType = result = newTypeS(tyTypeDesc, c) result.addSonSkipIntLit(typ.AssertNotNil) proc newTypeS(kind: TTypeKind, c: PContext): PType = result = newType(kind, getCurrOwner()) proc errorType*(c: PContext): PType = ## creates a type representing an error state result = newTypeS(tyError, c) proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind dest.owner = getCurrOwner() dest.size = - 1 proc makeRangeType*(c: PContext, first, last: biggestInt, info: TLineInfo): PType = var n = newNodeI(nkRange, info) addSon(n, newIntNode(nkIntLit, first)) addSon(n, newIntNode(nkIntLit, last)) result = newTypeS(tyRange, c) result.n = n rawAddSon(result, getSysType(tyInt)) # basetype of range proc markIndirect*(c: PContext, s: PSym) {.inline.} = if s.kind in {skProc, skConverter, skMethod, skIterator}: incl(s.flags, sfAddrTaken) # XXX add to 'c' for global analysis proc illFormedAst*(n: PNode) = GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) proc checkSonsLen*(n: PNode, length: int) = if sonsLen(n) != length: illFormedAst(n) proc checkMinSonsLen*(n: PNode, length: int) = if sonsLen(n) < length: illFormedAst(n)