diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/commands.nim | 4 | ||||
-rw-r--r-- | compiler/extccomp.nim | 49 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 65 |
5 files changed, 117 insertions, 7 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim index fc28577aa..dba117516 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -612,6 +612,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "experimental": expectNoArg(switch, arg, pass, info) gExperimentalMode = true + of "assembler": + cAssembler = nameToCC(arg) + if cAssembler notin cValidAssemblers: + localError(info, errGenerated, "'$1' is not a valid assembler." % [arg]) else: if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 44a13e2f4..683de67e0 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -19,7 +19,7 @@ import type TSystemCC* = enum ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, - ccTcc, ccPcc, ccUcc, ccIcl + ccTcc, ccPcc, ccUcc, ccIcl, asmFasm TInfoCCProp* = enum # properties of the C compiler: hasSwitchRange, # CC allows ranges in switch statements (GNU C) hasComputedGoto, # CC has computed goto (GNU C extension) @@ -318,6 +318,31 @@ compiler ucc: packedPragma: "", # XXX: not supported yet props: {}) +# fasm assembler +compiler fasm: + result = ( + name: "fasm", + objExt: "o", + optSpeed: "", + optSize: "", + compilerExe: "fasm", + cppCompiler: "fasm", + compileTmpl: "$file $objfile", + buildGui: "", + buildDll: "", + buildLib: "", + linkerExe: "", + linkTmpl: "", + includeCmd: "", + linkDirCmd: "", + linkLibCmd: "", + debug: "", + pic: "", + asmStmtFrmt: "", + structStmtFmt: "", + packedPragma: "", + props: {}) + const CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [ gcc(), @@ -331,17 +356,22 @@ const tcc(), pcc(), ucc(), - icl()] + icl(), + fasm()] hExt* = ".h" var cCompiler* = ccGcc # the used compiler + cAssembler* = ccNone gMixedMode*: bool # true if some module triggered C++ codegen cIncludes*: seq[string] = @[] # directories to search for included files cLibs*: seq[string] = @[] # directories to search for lib files cLinkedLibs*: seq[string] = @[] # libraries to link +const + cValidAssemblers* = {asmFasm} + # implementation proc libNameTmpl(): string {.inline.} = @@ -527,6 +557,21 @@ proc getLinkerExe(compiler: TSystemCC): string = proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = var c = cCompiler + if cfilename.endswith(".asm"): + var customAssembler = getConfigVar("assembler") + if customAssembler.len > 0: + c = nameToCC(customAssembler) + else: + if targetCPU == cpuI386 or targetCPU == cpuAmd64: + c = asmFasm + else: + c = ccNone + + if c == ccNone: + rawMessage(errExternalAssemblerNotFound, "") + elif c notin cValidAssemblers: + rawMessage(errExternalAssemblerNotValid, customAssembler) + var options = cFileSpecificOptions(cfilename) var exe = getConfigVar(c, ".exe") if exe.len == 0: exe = c.getCompilerExe diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 9bff6c123..1b1f0a76e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -108,6 +108,8 @@ type errCannotInferReturnType, errGenericLambdaNotAllowed, errCompilerDoesntSupportTarget, + errExternalAssemblerNotFound, + errExternalAssemblerNotValid, errUser, warnCannotOpenFile, warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, @@ -371,6 +373,8 @@ const "it is used as an operand to another routine and the types " & "of the generic paramers can be inferred from the expected signature.", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", + errExternalAssemblerNotFound: "External assembler not found", + errExternalAssemblerNotValid: "External assembler '$1' is not a valid assembler", errUser: "$1", warnCannotOpenFile: "cannot open \'$1\'", warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 128a90138..5f317ed24 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -395,6 +395,8 @@ proc processCompile(c: PContext, n: PNode) = var found = findFile(s) if found == "": found = s var trunc = changeFileExt(found, "") + if not isAbsolute(found): + found = parentDir(n.info.toFullPath) / found extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ef1c01b7a..357c6cf32 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -58,6 +58,10 @@ type isSubtype, isSubrange, # subrange of the wanted type; no type conversion # but apart from that counts as ``isSubtype`` + isBothMetaConvertible # generic proc parameter was matched against + # generic type, e.g., map(mySeq, x=>x+1), + # maybe recoverable by rerun if the parameter is + # the proc's return value isInferred, # generic proc was matched against a concrete type isInferredConvertible, # same as above, but requiring proc CC conversion isGeneric, @@ -389,9 +393,30 @@ proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = - var f = f + ## For example we have: + ## .. code-block:: nim + ## proc myMap[T,S](sIn: seq[T], f: proc(x: T): S): seq[S] = ... + ## proc innerProc[Q,W](q: Q): W = ... + ## And we want to match: myMap(@[1,2,3], innerProc) + ## This proc (procParamTypeRel) will do the following steps in + ## three different calls: + ## - matches f=T to a=Q. Since f is metatype, we resolve it + ## to int (which is already known at this point). So in this case + ## Q=int mapping will be saved to c.bindings. + ## - matches f=S to a=W. Both of these metatypes are unknown, so we + ## return with isBothMetaConvertible to ask for rerun. + ## - matches f=S to a=W. At this point the return type of innerProc + ## is known (we get it from c.bindings). We can use that value + ## to match with f, and save back to c.bindings. + var + f = f + a = a if a.isMetaType: + let aResolved = PType(idTableGet(c.bindings, a)) + if aResolved != nil: + a = aResolved + if a.isMetaType: if f.isMetaType: # We are matching a generic proc (as proc param) # to another generic type appearing in the proc @@ -401,12 +426,15 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = f = generateTypeInstance(c.c, c.bindings, c.call.info, f) if f == nil or f.isMetaType: # no luck resolving the type, so the inference fails - return isNone + return isBothMetaConvertible + # Note that this typeRel call will save a's resolved type into c.bindings let reverseRel = typeRel(c, a, f) if reverseRel >= isGeneric: result = isInferred #inc c.genericMatches else: + # Note that this typeRel call will save f's resolved type into c.bindings + # if f is metatype. result = typeRel(c, f, a) if result <= isSubtype or inconsistentVarTypes(f, a): @@ -450,8 +478,9 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = elif f.callConv != a.callConv: # valid to pass a 'nimcall' thingie to 'closure': if f.callConv == ccClosure and a.callConv == ccDefault: - result = if result != isInferred: isConvertible - else: isInferredConvertible + result = if result == isInferred: isInferredConvertible + elif result == isBothMetaConvertible: isBothMetaConvertible + else: isConvertible else: return isNone when useEffectSystem: @@ -1225,7 +1254,7 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) = case r of isConvertible, isIntConv: inc(m.convMatches, convMatch) of isSubtype, isSubrange: inc(m.subtypeMatches) - of isGeneric, isInferred: inc(m.genericMatches) + of isGeneric, isInferred, isBothMetaConvertible: inc(m.genericMatches) of isFromIntLit: inc(m.intConvMatches, 256) of isInferredConvertible: inc(m.convMatches) @@ -1291,6 +1320,29 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, put(m.bindings, f, inlined) return argSemantized + # If r == isBothMetaConvertible then we rerun typeRel. + # bothMetaCounter is for safety to avoid any infinite loop, + # I don't have any example when it is needed. + # lastBindingsLenth is used to check whether m.bindings remains the same, + # because in that case there is no point in continuing. + var bothMetaCounter = 0 + var lastBindingsLength = -1 + while r == isBothMetaConvertible and + lastBindingsLength != m.bindings.counter and + bothMetaCounter < 100: + lastBindingsLength = m.bindings.counter + inc(bothMetaCounter) + if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds: + result = c.semInferredLambda(c, m.bindings, arg) + elif arg.kind != nkSym: + return nil + else: + let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info) + result = newSymNode(inferred, arg.info) + inc(m.convMatches) + arg = result + r = typeRel(m, f, arg.typ) + case r of isConvertible: inc(m.convMatches) @@ -1336,6 +1388,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result.typ = getInstantiatedType(c, arg, m, f) else: result = arg + of isBothMetaConvertible: + # This is the result for the 101th time. + result = nil of isFromIntLit: # too lazy to introduce another ``*matches`` field, so we conflate # ``isIntConv`` and ``isIntLit`` here: |