diff options
-rw-r--r-- | compiler/commands.nim | 34 | ||||
-rw-r--r-- | compiler/main.nim | 6 | ||||
-rw-r--r-- | compiler/nim.nim | 6 | ||||
-rw-r--r-- | compiler/pretty.nim | 12 | ||||
-rw-r--r-- | compiler/service.nim | 30 | ||||
-rw-r--r-- | compiler/vmgen.nim | 25 | ||||
-rw-r--r-- | lib/pure/asynchttpserver.nim | 2 | ||||
-rw-r--r-- | tests/vm/tasmparser.nim | 174 | ||||
-rw-r--r-- | tests/vm/tcompiletimetable.nim | 11 | ||||
-rw-r--r-- | todo.txt | 4 |
10 files changed, 249 insertions, 55 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim index 54d2ed6a4..2a2e0c4ee 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, - wordrecg, parseutils, nimblecmd, idents + wordrecg, parseutils, nimblecmd, idents, parseopt # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -43,7 +43,7 @@ type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line - passPP # preprocessor called ProcessCommand() + passPP # preprocessor called processCommand() proc processCommand*(switch: string, pass: TCmdLinePass) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) @@ -573,3 +573,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo) + + +var + arguments* = "" + # the arguments to be passed to the program that + # should be run + +proc processSwitch*(pass: TCmdLinePass; p: OptParser) = + # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") + # we fix this here + var bracketLe = strutils.find(p.key, '[') + if bracketLe >= 0: + var key = substr(p.key, 0, bracketLe - 1) + var val = substr(p.key, bracketLe + 1) & ':' & p.val + processSwitch(key, val, pass, gCmdLineInfo) + else: + processSwitch(p.key, p.val, pass, gCmdLineInfo) + +proc processArgument*(pass: TCmdLinePass; p: OptParser; + argsCount: var int): bool = + if argsCount == 0: + options.command = p.key + else: + if pass == passCmd1: options.commandArgs.add p.key + if argsCount == 1: + # support UNIX style filenames anywhere for portable build scripts: + options.gProjectName = unixToNativePath(p.key) + arguments = cmdLineRest(p) + result = true + inc argsCount diff --git a/compiler/main.nim b/compiler/main.nim index 58833f60c..0bb057df5 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -164,12 +164,6 @@ proc commandEval(exp: string) = var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" evalNim(echoExp.parseString, makeStdinModule()) -proc commandPrettyOld = - var projectFile = addFileExt(mainCommandArg(), NimExt) - var module = parseFile(projectFile.fileInfoIdx) - if module != nil: - renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt)) - proc commandPretty = msgs.gErrorMax = high(int) # do not stop after first error semanticPasses() diff --git a/compiler/nim.nim b/compiler/nim.nim index 27222ca57..a87e0a1ac 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -58,7 +58,7 @@ proc handleCmdLine() = if msgs.gErrorCounter == 0: when hasTinyCBackend: if gCmd == cmdRun: - tccgen.run(service.arguments) + tccgen.run(commands.arguments) if optRun in gGlobalOptions: if gCmd == cmdCompileToJS: var ex: string @@ -67,7 +67,7 @@ proc handleCmdLine() = else: ex = quoteShell( completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) - execExternalProgram("node " & ex & ' ' & service.arguments) + execExternalProgram("node " & ex & ' ' & commands.arguments) else: var binPath: string if options.outFile.len > 0: @@ -77,7 +77,7 @@ proc handleCmdLine() = # Figure out ourselves a valid binary name. binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir var ex = quoteShell(binPath) - execExternalProgram(ex & ' ' & service.arguments) + execExternalProgram(ex & ' ' & commands.arguments) when declared(GC_setMaxPause): GC_setMaxPause 2_000 diff --git a/compiler/pretty.nim b/compiler/pretty.nim index dfc164208..6ee931951 100644 --- a/compiler/pretty.nim +++ b/compiler/pretty.nim @@ -14,14 +14,20 @@ import strutils, os, options, ast, astalgo, msgs, ropes, idents, passes, intsets, strtabs, semdata, prettybase + +type + StyleCheck* {.pure.} = enum None, Confirm, Auto + +var + gOverWrite* = true + gStyleCheck*: StyleCheck + gCheckExtern*: bool + type TGen = object of TPassContext module*: PSym PGen = ref TGen -var - gCheckExtern: bool - proc overwriteFiles*() = let overWrite = options.getConfigVar("pretty.overwrite").normalize != "off" let doStrip = options.getConfigVar("pretty.strip").normalize == "on" diff --git a/compiler/service.nim b/compiler/service.nim index f0eeb0ed5..4a1b296cd 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -25,39 +25,17 @@ var lastCaasCmd* = "" # in caas mode, the list of defines and options will be given at start-up? # it's enough to check that the previous compilation command is the same? - arguments* = "" - # the arguments to be passed to the program that - # should be run proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) var argsCount = 0 - while true: + while true: parseopt.next(p) case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: - # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") - # we fix this here - var bracketLe = strutils.find(p.key, '[') - if bracketLe >= 0: - var key = substr(p.key, 0, bracketLe - 1) - var val = substr(p.key, bracketLe + 1) & ':' & p.val - processSwitch(key, val, pass, gCmdLineInfo) - else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + of cmdEnd: break + of cmdLongoption, cmdShortOption: processSwitch(pass, p) of cmdArgument: - if argsCount == 0: - options.command = p.key - else: - if pass == passCmd1: options.commandArgs.add p.key - if argsCount == 1: - # support UNIX style filenames anywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) - break - inc argsCount - + if processArgument(pass, p, argsCount): break if pass == passCmd2: if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 05c894ee3..718c07243 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -43,18 +43,19 @@ type proc debugInfo(info: TLineInfo): string = result = info.toFilename.splitFile.name & ":" & $info.line -proc codeListing(c: PCtx, result: var string, start=0) = +proc codeListing(c: PCtx, result: var string, start=0; last = -1) = # first iteration: compute all necessary labels: var jumpTargets = initIntSet() - - for i in start.. < c.code.len: + + let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1) + for i in start..last: let x = c.code[i] if x.opcode in relativeJumps: jumpTargets.incl(i+x.regBx-wordExcess) # for debugging purposes var i = start - while i < c.code.len: + while i <= last: if i in jumpTargets: result.addf("L$1:\n", i) let x = c.code[i] @@ -82,9 +83,9 @@ proc codeListing(c: PCtx, result: var string, start=0) = result.add("\n") inc i -proc echoCode*(c: PCtx, start=0) {.deprecated.} = +proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} = var buf = "" - codeListing(c, buf, start) + codeListing(c, buf, start, last) echo buf proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) = @@ -495,6 +496,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = c.freeTempRange(x, n.len) template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar +proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym) proc needsAsgnPatch(n: PNode): bool = n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, @@ -637,8 +639,10 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) = c.freeTemp(tmp) proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) = + var x = n.sons[1] + if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0] let - dest = c.genx(n.sons[1], {gfAddrOf}) + dest = c.genx(x) tmp = c.genx(n.sons[2]) c.gABC(n, opc, dest, tmp, 0) #c.genAsgnPatch(n.sons[1], dest) @@ -1053,6 +1057,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; # nkAddr we must not use 'unneededIndirection', but for deref we use it. if not isAddr and unneededIndirection(n.sons[0]): gen(c, n.sons[0], dest, newflags) + elif isGlobal(n.sons[0]): + gen(c, n.sons[0], dest, flags+{gfAddrOf}) else: let tmp = c.genx(n.sons[0], newflags) if dest < 0: dest = c.getTemp(n.typ) @@ -1062,6 +1068,9 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opcNodeToReg, dest, dest) elif c.prc.slots[tmp].kind >= slotTempUnknown: gABC(c, n, opcAddrNode, dest, tmp) + # XXX this can still be wrong sometimes; hopefully it's only generated + # in call contexts, where it is safe + #message(n.info, warnUser, "suspicious opcode used") else: gABC(c, n, opcAddrReg, dest, tmp) c.freeTemp(tmp) @@ -1247,6 +1256,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = c.gABx(n, opcLdGlobal, cc, s.position) c.gABC(n, opcNodeToReg, dest, cc) c.freeTemp(cc) + elif gfAddrOf in flags: + c.gABx(n, opcLdGlobalAddr, dest, s.position) else: c.gABx(n, opcLdGlobal, dest, s.position) else: diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index e2e9e1881..c2cb7e15c 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -187,7 +187,7 @@ proc processClient(client: PAsyncSocket, address: string, request.client.close() break -proc serve*(server: PAsyncHttpServer, port: TPort, +proc serve*(server: PAsyncHttpServer, port: Port, callback: proc (request: TRequest): PFuture[void] {.closure,gcsafe.}, address = "") {.async.} = ## Starts the process of listening for incoming HTTP connections on the diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim new file mode 100644 index 000000000..24ccb2ec8 --- /dev/null +++ b/tests/vm/tasmparser.nim @@ -0,0 +1,174 @@ + +# bug #1513 + +import os, parseutils, strutils, ropes, macros + +var + code {.compileTime.} = "" + start {.compileTime.} = 0 + line {.compileTime.} = 1 + cpp {.compileTime.} = "" + token {.compileTime.} = "" + +proc log (msg: string) {.compileTime.} = + echo msg + +proc asmx64 () {.compileTime} = + + #log "code = $1" % code + + const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {" + const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} " + + const xp = "x." + + const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' } + const symbol = { '0'..'9' } + symbolStart + const eolComment = { ';' } + const endOfLine = { '\l', '\r' } + const leadingWhiteSpace = { ' ' } + + const end_or_comment = endOfLine + eolComment + { '\0' } + + const passthrough_start = { '{', '`' } + const passthrough_end = { '}', '`', '\0' } + + const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start + + + proc abortAsmParse (err:string) = + # + + let codeLen = code.len + #let codeEnd = codeLen-1 + cpp.add asmx64pre + + #log "{$1}\n" % [code] + + type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine + + var state:asmParseState = leading + + proc checkEnd (err:string) = + let ch = code [start] + if int (ch) == 0: + abortAsmParse (err) + + proc get_passthrough () = + inc start + let prev_start = start + let prev_token = token + start += code.parseUntil (token, passthrough_end, start) + checkEnd ("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code [prev_start-prev_token.len..prev_start]), token[1..token.len-1]]) + inc start + cpp.add "`" + cpp.add token + cpp.add "`" + + var inparse = true + + proc checkCmdEnd () = + if codeLen == start: + state = endCmd + inparse = false + + while inparse: + checkCmdEnd () + + log ("state=$1 start=$2" % [$state, $start]) + + case state: + of leading: + + echo "b100 ", start + start += code.skipWhile (leadingWhiteSpace, start) + echo "b200 ", start + let ch = code [start] + if ch in endOfLine: + inc (line) + #echo "c100 ", start, ' ', code + start += code.skipWhile (endOfline, start) + #echo "c200 ", start, ' ', code + continue + elif ch in symbolStart: + state = mnemonic + elif ch in eolComment: + state = skipToEndOfLine + elif ch in passthrough_start: + get_passthrough () + echo "d100 ", start + start += code.parseUntil (token, end_or_symbol_or_comment_or_passthrough, start) + echo "d200 ", start + cpp.add token + state = mnemonic + elif int (ch) == 0: + break + else: + abortAsmParse ("after '$3' illegal character at offset $1: $2" % [$start, $(int (ch)), token]) + + of mnemonic: + echo "e100 ", start + start += code.parseWhile (token, symbol, start) + echo "e200 ", start + cpp.add xp + cpp.add token + cpp.add "(" + state = betweenArguments + + of betweenArguments: + let tmp = start + let rcode = code + start += rcode.parseUntil (token, end_or_symbol_or_comment_or_passthrough, tmp) + cpp.add token + + if codeLen <= start: + state = endCmd + continue + + let ch = code [start] + if ch in passthrough_start: + get_passthrough () + continue + if (ch in {'x', 'X'}) and ('0' == code [start-1]): + token = $(code [start]) + cpp.add token + inc start + continue + state = arguments + + of arguments: + if code [start] in end_or_comment: + state = endCmd + continue + start += code.parseWhile (token, symbol, start) + cpp.add xp + cpp.add token + state = betweenArguments + + of endCmd: + cpp.add ");\n" + state = skipToEndOfLine + + of skipToEndOfLine: + echo "a100 ", start + start += code.skipUntil (endOfLine, start) + echo "a200 ", start + start += code.skipWhile (endOfline, start) + echo "a300 ", start + inc line + state = leading + + cpp.add asmx64post + + echo ($cpp) + +macro asmx64x (code_in:expr) : stmt = + code = $code_in + echo ("code.len = $1, code = >>>$2<<<" % [$code.len, code]) + asmx64 () + discard result + +asmx64x """ + mov rax, {m} + ret +""" diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim index f1d3ecd4e..df6ead56f 100644 --- a/tests/vm/tcompiletimetable.nim +++ b/tests/vm/tcompiletimetable.nim @@ -2,18 +2,19 @@ discard """ msg: '''2 3 4:2 - ''' +Got Hi +Got Hey''' """ # bug #404 -import macros, tables +import macros, tables, strtabs var ZOOT{.compileTime.} = initTable[int, int](2) var iii {.compiletime.} = 1 macro zoo:stmt= - zoot[iii] = iii*2 + ZOOT[iii] = iii*2 inc iii echo iii @@ -29,9 +30,7 @@ tupleUnpack # bug #903 -import strtabs - -var x {.compileTime.}: PStringTable +var x {.compileTime.}: StringTableRef macro addStuff(stuff, body: expr): stmt {.immediate.} = result = newNimNode(nnkStmtList) diff --git a/todo.txt b/todo.txt index 319704925..acdec7547 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,9 @@ version 0.10 ============ -- Test nim pretty on various babel packages +- Write new nimfix tool +- Test nimfix on various babel packages +- Pegs do not work at compile-time version 0.9.6 |