summary refs log tree commit diff stats
path: root/rod/commands.nim
diff options
context:
space:
mode:
Diffstat (limited to 'rod/commands.nim')
-rwxr-xr-xrod/commands.nim422
1 files changed, 422 insertions, 0 deletions
diff --git a/rod/commands.nim b/rod/commands.nim
new file mode 100755
index 000000000..c080b23e3
--- /dev/null
+++ b/rod/commands.nim
@@ -0,0 +1,422 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module handles the parsing of command line arguments.
+
+import 
+  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, 
+  wordrecg
+
+proc writeCommandLineUsage*()
+
+type 
+  TCmdLinePass* = enum 
+    passCmd1,                 # first pass over the command line
+    passCmd2,                 # second pass over the command line
+    passPP                    # preprocessor called ProcessCommand()
+
+proc ProcessCommand*(switch: string, pass: TCmdLinePass)
+proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
+# implementation
+
+const 
+  HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]" &
+      "\n" & "Copyright (c) 2004-2009 by Andreas Rumpf" & "\n"
+
+const 
+  Usage = """
+Usage::
+  nimrod command [options] inputfile [arguments]
+Command::
+  compile, c                compile project with default code generator (C)
+  compileToC, cc            compile project with C code generator
+  doc                       generate the documentation for inputfile
+  rst2html                  converts a reStructuredText file to HTML
+  rst2tex                   converts a reStructuredText file to TeX
+Arguments:
+  arguments are passed to the program being run (if --run option is selected)
+Options:
+  -p, --path:PATH           add path to search paths
+  -o, --out:FILE            set the output filename
+  -d, --define:SYMBOL       define a conditional symbol
+  -u, --undef:SYMBOL        undefine a conditional symbol
+  -f, --forceBuild          force rebuilding of all modules
+  --symbolFiles:on|off      use symbol files to speed up compilation (buggy!)
+  --stackTrace:on|off       code generation for stack trace ON|OFF
+  --lineTrace:on|off        code generation for line trace ON|OFF
+  --debugger:on|off         turn Embedded Nimrod Debugger ON|OFF
+  -x, --checks:on|off       code generation for all runtime checks ON|OFF
+  --objChecks:on|off        code generation for obj conversion checks ON|OFF
+  --fieldChecks:on|off      code generation for case variant fields ON|OFF
+  --rangeChecks:on|off      code generation for range checks ON|OFF
+  --boundChecks:on|off      code generation for bound checks ON|OFF
+  --overflowChecks:on|off   code generation for over-/underflow checks ON|OFF
+  -a, --assertions:on|off   code generation for assertions ON|OFF
+  --deadCodeElim:on|off     whole program dead code elimination ON|OFF
+  --opt:none|speed|size     optimize not at all or for speed|size
+  --app:console|gui|lib     generate a console|GUI application|dynamic library
+  -r, --run                 run the compiled program with given arguments
+  --advanced                show advanced command line switches
+  -h, --help                show this help
+"""
+        
+  AdvancedUsage = """
+Advanced commands::
+  pas                       convert a Pascal file to Nimrod syntax
+  pretty                    pretty print the inputfile
+  genDepend                 generate a DOT file containing the
+                            module dependency graph
+  listDef                   list all defined conditionals and exit
+  check                     checks the project for syntax and semantic
+  parse                     parses a single file (for debugging Nimrod)
+Advanced options:
+  -w, --warnings:on|off     warnings ON|OFF
+  --warning[X]:on|off       specific warning X ON|OFF
+  --hints:on|off            hints ON|OFF
+  --hint[X]:on|off          specific hint X ON|OFF
+  --lib:PATH                set the system library path
+  -c, --compileOnly         compile only; do not assemble or link
+  --noLinking               compile but do not link
+  --noMain                  do not generate a main procedure
+  --genScript               generate a compile script (in the 'nimcache'
+                            subdirectory named 'compile_$project$scriptext')
+  --os:SYMBOL               set the target operating system (cross-compilation)
+  --cpu:SYMBOL              set the target processor (cross-compilation)
+  --debuginfo               enables debug information
+  -t, --passc:OPTION        pass an option to the C compiler
+  -l, --passl:OPTION        pass an option to the linker
+  --genMapping              generate a mapping file containing
+                            (Nimrod, mangled) identifier pairs
+  --lineDir:on|off          generation of #line directive ON|OFF
+  --checkpoints:on|off      turn on|off checkpoints; for debugging Nimrod
+  --skipCfg                 do not read the general configuration file
+  --skipProjCfg             do not read the project's configuration file
+  --gc:refc|boehm|none      use Nimrod's native GC|Boehm GC|no GC
+  --index:FILE              use FILE to generate a documenation index file
+  --putenv:key=value        set an environment variable
+  --listCmd                 list the commands used to execute external programs
+  --parallelBuild=0|1|...   perform a parallel build
+                            value = number of processors (0 for auto-detect)
+  --verbosity:0|1|2|3       set Nimrod's verbosity level (0 is default)
+  -v, --version             show detailed version information
+"""
+
+proc getCommandLineDesc(): string = 
+  result = `%`(HelpMessage, [VersionAsString, platform.os[platform.hostOS].name, 
+                             cpu[platform.hostCPU].name]) & Usage
+
+var 
+  helpWritten: bool           # BUGFIX 19
+  versionWritten: bool
+  advHelpWritten: bool
+
+proc HelpOnError(pass: TCmdLinePass) = 
+  if (pass == passCmd1) and not helpWritten: 
+    # BUGFIX 19
+    MessageOut(getCommandLineDesc())
+    helpWritten = true
+    quit(0)
+
+proc writeAdvancedUsage(pass: TCmdLinePass) = 
+  if (pass == passCmd1) and not advHelpWritten: 
+    # BUGFIX 19
+    MessageOut(`%`(HelpMessage, [VersionAsString, 
+                                 platform.os[platform.hostOS].name, 
+                                 cpu[platform.hostCPU].name]) & AdvancedUsage)
+    advHelpWritten = true
+    helpWritten = true
+    quit(0)
+
+proc writeVersionInfo(pass: TCmdLinePass) = 
+  if (pass == passCmd1) and not versionWritten: 
+    versionWritten = true
+    helpWritten = true
+    messageOut(`%`(HelpMessage, [VersionAsString, 
+                                 platform.os[platform.hostOS].name, 
+                                 cpu[platform.hostCPU].name]))
+    quit(0)
+
+proc writeCommandLineUsage() = 
+  if not helpWritten: 
+    messageOut(getCommandLineDesc())
+    helpWritten = true
+
+proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = 
+  liMessage(info, errInvalidCmdLineOption, switch)
+
+proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, 
+                 info: TLineInfo) = 
+  var i: int
+  cmd = ""
+  i = 0
+  if (i < len(switch) + 0) and (switch[i] == '-'): inc(i)
+  if (i < len(switch) + 0) and (switch[i] == '-'): inc(i)
+  while i < len(switch) + 0: 
+    case switch[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
+    else: break 
+    inc(i)
+  if i >= len(switch) + 0: arg = ""
+  elif switch[i] in {':', '=', '['}: arg = copy(switch, i + 1)
+  else: InvalidCmdLineOption(pass, switch, info)
+  
+proc ProcessOnOffSwitch(op: TOptions, arg: string, pass: TCmdlinePass, 
+                        info: TLineInfo) = 
+  case whichKeyword(arg)
+  of wOn: gOptions = gOptions + op
+  of wOff: gOptions = gOptions - op
+  else: liMessage(info, errOnOrOffExpectedButXFound, arg)
+  
+proc ProcessOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdlinePass, 
+                         info: TLineInfo) = 
+  case whichKeyword(arg)
+  of wOn: gGlobalOptions = gGlobalOptions + op
+  of wOff: gGlobalOptions = gGlobalOptions - op
+  else: liMessage(info, errOnOrOffExpectedButXFound, arg)
+  
+proc ExpectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+  if (arg == ""): liMessage(info, errCmdLineArgExpected, switch)
+  
+proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+  if (arg != ""): liMessage(info, errCmdLineNoArgExpected, switch)
+  
+proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass, 
+                         info: TLineInfo) = 
+  var 
+    i, x: int
+    n: TNoteKind
+    id: string
+  id = ""                     # arg = "X]:on|off"
+  i = 0
+  n = hintMin
+  while (i < len(arg) + 0) and (arg[i] != ']'): 
+    add(id, arg[i])
+    inc(i)
+  if (i < len(arg) + 0) and (arg[i] == ']'): inc(i)
+  else: InvalidCmdLineOption(pass, arg, info)
+  if (i < len(arg) + 0) and (arg[i] in {':', '='}): inc(i)
+  else: InvalidCmdLineOption(pass, arg, info)
+  if state == wHint: 
+    x = findStr(msgs.HintsToStr, id)
+    if x >= 0: n = TNoteKind(x + ord(hintMin))
+    else: InvalidCmdLineOption(pass, arg, info)
+  else: 
+    x = findStr(msgs.WarningsToStr, id)
+    if x >= 0: n = TNoteKind(x + ord(warnMin))
+    else: InvalidCmdLineOption(pass, arg, info)
+  case whichKeyword(copy(arg, i))
+  of wOn: incl(gNotes, n)
+  of wOff: excl(gNotes, n)
+  else: liMessage(info, errOnOrOffExpectedButXFound, arg)
+  
+proc processPath(path: string): string = 
+  result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath])
+
+proc processCompile(filename: string) = 
+  var found, trunc: string
+  found = findFile(filename)
+  if found == "": found = filename
+  trunc = changeFileExt(found, "")
+  extccomp.addExternalFileToCompile(trunc)
+  extccomp.addFileToLink(completeCFilePath(trunc, false))
+
+proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = 
+  var 
+    theOS: TSystemOS
+    cpu: TSystemCPU
+    key, val, path: string
+  case whichKeyword(switch)
+  of wPath, wP: 
+    expectArg(switch, arg, pass, info)
+    path = processPath(arg)
+    discard lists.IncludeStr(options.searchPaths, path)
+  of wOut, wO: 
+    expectArg(switch, arg, pass, info)
+    options.outFile = arg
+  of wDefine, wD: 
+    expectArg(switch, arg, pass, info)
+    DefineSymbol(arg)
+  of wUndef, wU: 
+    expectArg(switch, arg, pass, info)
+    UndefSymbol(arg)
+  of wCompile: 
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: processCompile(arg)
+  of wLink: 
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: addFileToLink(arg)
+  of wDebuginfo: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optCDebug)
+  of wCompileOnly, wC: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optCompileOnly)
+  of wNoLinking: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optNoLinking)
+  of wNoMain: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optNoMain)
+  of wForceBuild, wF: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optForceFullMake)
+  of wGC: 
+    expectArg(switch, arg, pass, info)
+    case whichKeyword(arg)
+    of wBoehm: 
+      incl(gGlobalOptions, optBoehmGC)
+      excl(gGlobalOptions, optRefcGC)
+      DefineSymbol("boehmgc")
+    of wRefc: 
+      excl(gGlobalOptions, optBoehmGC)
+      incl(gGlobalOptions, optRefcGC)
+    of wNone: 
+      excl(gGlobalOptions, optRefcGC)
+      excl(gGlobalOptions, optBoehmGC)
+      defineSymbol("nogc")
+    else: liMessage(info, errNoneBoehmRefcExpectedButXFound, arg)
+  of wWarnings, wW: ProcessOnOffSwitch({optWarns}, arg, pass, info)
+  of wWarning: ProcessSpecificNote(arg, wWarning, pass, info)
+  of wHint: ProcessSpecificNote(arg, wHint, pass, info)
+  of wHints: ProcessOnOffSwitch({optHints}, arg, pass, info)
+  of wCheckpoints: ProcessOnOffSwitch({optCheckpoints}, arg, pass, info)
+  of wStackTrace: ProcessOnOffSwitch({optStackTrace}, arg, pass, info)
+  of wLineTrace: ProcessOnOffSwitch({optLineTrace}, arg, pass, info)
+  of wDebugger: 
+    ProcessOnOffSwitch({optEndb}, arg, pass, info)
+    if optEndb in gOptions: DefineSymbol("endb")
+    else: UndefSymbol("endb")
+  of wProfiler: 
+    ProcessOnOffSwitch({optProfiler}, arg, pass, info)
+    if optProfiler in gOptions: DefineSymbol("profiler")
+    else: UndefSymbol("profiler")
+  of wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info)
+  of wObjChecks: ProcessOnOffSwitch({optObjCheck}, arg, pass, info)
+  of wFieldChecks: ProcessOnOffSwitch({optFieldCheck}, arg, pass, info)
+  of wRangeChecks: ProcessOnOffSwitch({optRangeCheck}, arg, pass, info)
+  of wBoundChecks: ProcessOnOffSwitch({optBoundsCheck}, arg, pass, info)
+  of wOverflowChecks: ProcessOnOffSwitch({optOverflowCheck}, arg, pass, info)
+  of wLineDir: ProcessOnOffSwitch({optLineDir}, arg, pass, info)
+  of wAssertions, wA: ProcessOnOffSwitch({optAssert}, arg, pass, info)
+  of wDeadCodeElim: ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
+  of wOpt: 
+    expectArg(switch, arg, pass, info)
+    case whichKeyword(arg)
+    of wSpeed: 
+      incl(gOptions, optOptimizeSpeed)
+      excl(gOptions, optOptimizeSize)
+    of wSize: 
+      excl(gOptions, optOptimizeSpeed)
+      incl(gOptions, optOptimizeSize)
+    of wNone: 
+      excl(gOptions, optOptimizeSpeed)
+      excl(gOptions, optOptimizeSize)
+    else: liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg)
+  of wApp: 
+    expectArg(switch, arg, pass, info)
+    case whichKeyword(arg)
+    of wGui: 
+      incl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("guiapp")
+    of wConsole: 
+      excl(gGlobalOptions, optGenGuiApp)
+    of wLib: 
+      incl(gGlobalOptions, optGenDynLib)
+      excl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("library")
+    else: liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg)
+  of wListDef: 
+    expectNoArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: condsyms.listSymbols()
+  of wPassC, wT: 
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
+  of wPassL, wL: 
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
+  of wIndex: 
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: gIndexFile = arg
+  of wImport: 
+    expectArg(switch, arg, pass, info)
+    options.addImplicitMod(arg)
+  of wListCmd: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optListCmd)
+  of wGenMapping: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optGenMapping)
+  of wOS: 
+    expectArg(switch, arg, pass, info)
+    if (pass == passCmd1): 
+      theOS = platform.NameToOS(arg)
+      if theOS == osNone: liMessage(info, errUnknownOS, arg)
+      if theOS != platform.hostOS: 
+        setTarget(theOS, targetCPU)
+        incl(gGlobalOptions, optCompileOnly)
+        condsyms.InitDefines()
+  of wCPU: 
+    expectArg(switch, arg, pass, info)
+    if (pass == passCmd1): 
+      cpu = platform.NameToCPU(arg)
+      if cpu == cpuNone: liMessage(info, errUnknownCPU, arg)
+      if cpu != platform.hostCPU: 
+        setTarget(targetOS, cpu)
+        incl(gGlobalOptions, optCompileOnly)
+        condsyms.InitDefines()
+  of wRun, wR: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optRun)
+  of wVerbosity: 
+    expectArg(switch, arg, pass, info)
+    gVerbosity = parseInt(arg)
+  of wParallelBuild: 
+    expectArg(switch, arg, pass, info)
+    gNumberOfProcessors = parseInt(arg)
+  of wVersion, wV: 
+    expectNoArg(switch, arg, pass, info)
+    writeVersionInfo(pass)
+  of wAdvanced: 
+    expectNoArg(switch, arg, pass, info)
+    writeAdvancedUsage(pass)
+  of wHelp, wH: 
+    expectNoArg(switch, arg, pass, info)
+    helpOnError(pass)
+  of wSymbolFiles: 
+    ProcessOnOffSwitchG({optSymbolFiles}, arg, pass, info)
+  of wSkipCfg: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipConfigFile)
+  of wSkipProjCfg: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipProjConfigFile)
+  of wGenScript: 
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optGenScript)
+  of wLib: 
+    expectArg(switch, arg, pass, info)
+    libpath = processPath(arg)
+  of wPutEnv: 
+    expectArg(switch, arg, pass, info)
+    splitSwitch(arg, key, val, pass, info)
+    os.putEnv(key, val)
+  of wCC: 
+    expectArg(switch, arg, pass, info)
+    setCC(arg)
+  else: 
+    if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
+    else: InvalidCmdLineOption(pass, switch, info)
+  
+proc ProcessCommand(switch: string, pass: TCmdLinePass) = 
+  var 
+    cmd, arg: string
+    info: TLineInfo
+  info = newLineInfo("command line", 1, 1)
+  splitSwitch(switch, cmd, arg, pass, info)
+  ProcessSwitch(cmd, arg, pass, info)