diff --git a/compiler/ast.nim b/compiler/ast.nim index 13f7890bcd..34b00eed92 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -675,6 +675,9 @@ type TInstantiation* = object sym*: PSym concreteTypes*: seq[PType] + genericParamsCount*: int # for terrible reasons `concreteTypes` contains all the types, + # so we need to know how many generic params there were + # this is not serialized for IC and that is fine. compilesId*: CompilesId PInstantiation* = ref TInstantiation diff --git a/compiler/commands.nim b/compiler/commands.nim index ba3d5eadc8..2cd18185bb 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -473,6 +473,7 @@ proc parseCommand*(command: string): Command = of "cpp", "compiletocpp": cmdCompileToCpp of "objc", "compiletooc": cmdCompileToOC of "js", "compiletojs": cmdCompileToJS + of "nif": cmdCompileToNif of "r": cmdCrun of "m": cmdM of "run": cmdTcc @@ -507,6 +508,7 @@ proc setCmd*(conf: ConfigRef, cmd: Command) = of cmdCompileToCpp: conf.backend = backendCpp of cmdCompileToOC: conf.backend = backendObjc of cmdCompileToJS: conf.backend = backendJs + of cmdCompileToNif: conf.backend = backendNif else: discard proc setCommandEarly*(conf: ConfigRef, command: string) = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4bae400dc0..d4137e8364 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -341,7 +341,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = var fullSuffix = suffix case conf.backend of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix - of backendC: discard + of backendC, backendNif: discard of backendInvalid: # during parsing of cfg files; we don't know the backend yet, no point in # guessing wrong thing diff --git a/compiler/main.nim b/compiler/main.nim index 4c52317cfa..08b57722c4 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -117,6 +117,22 @@ when not defined(leanCompiler): else: raiseAssert $ext compilePipelineProject(graph) +proc commandCompileToNif(graph: ModuleGraph) = + let conf = graph.config + extccomp.initVars(conf) + if conf.symbolFiles == disabledSf: + if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"): + if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile): + # nothing changed + graph.config.notes = graph.config.mainPackageNotes + return + + if not extccomp.ccHasSaneOverflow(conf): + conf.symbols.defineSymbol("nimEmulateOverflowChecks") + + setPipeLinePass(graph, NifgenPass) + compilePipelineProject(graph) + proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config extccomp.initVars(conf) @@ -257,7 +273,7 @@ proc mainCommand*(graph: ModuleGraph) = if conf.exc == excNone: conf.exc = excSetjmp of backendCpp: if conf.exc == excNone: conf.exc = excCpp - of backendObjc: discard + of backendObjc, backendNif: discard of backendJs: if conf.hcrOn: # XXX: At the moment, system.nim cannot be compiled in JS mode @@ -275,6 +291,7 @@ proc mainCommand*(graph: ModuleGraph) = of backendCpp: commandCompileToC(graph) of backendObjc: commandCompileToC(graph) of backendJs: commandCompileToJS(graph) + of backendNif: commandCompileToNif(graph) of backendInvalid: raiseAssert "unreachable" template docLikeCmd(body) = diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 25ca73ad1f..6010e93947 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -60,6 +60,7 @@ type SemPass JSgenPass CgenPass + NifgenPass EvalPass InterpreterPass GenDependPass diff --git a/compiler/nifgen.nim b/compiler/nifgen.nim new file mode 100644 index 0000000000..63b993cddf --- /dev/null +++ b/compiler/nifgen.nim @@ -0,0 +1,1668 @@ +# +# +# The Nim Compiler +# (c) Copyright 2025 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the NIF code generator. + +import std / [assertions, syncio, os, tables, intsets] + +import + ast, astalgo, modulegraphs, options, pathutils, lineinfos, idents, msgs, types + +import "../dist/nimony/src/lib" / nifbuilder +import "../dist/nimony/src/models" / nifler_tags +import "../dist/nimony/src/gear2" / modnames + +## This was copied from Nifler's bridge.nim. However, this code will evolve +## in a different direction as it needs to translate the semchecked AST which +## is way more complex. For example, all magics need to be special cased. + +const + SystemModuleSuffix = "sysvq0asl" + +type + TranslationContext = object + conf: ConfigRef + b, deps: Builder + section: NiflerKind + portablePaths: bool + depsEnabled, lineInfoEnabled: bool + hasHoles: bool + graph: ModuleGraph + toSuffix: Table[FileIndex, string] + tempFilename, finalFilename: string # for atomic file creation + tempDepsFilename, finalDepsFilename: string # for atomic deps file creation + handled: IntSet + + NifModule* = ref object of PPassContext + graph*: ModuleGraph + module*: PSym + tc: TranslationContext + +proc nodeKindTranslation(k: TNodeKind): string = + case k + of nkCommand: "cmd" + of nkCall: "call" + of nkCallStrLit: "callstrlit" + of nkInfix: "infix" + of nkPrefix: "prefix" + of nkHiddenCallConv: "hiddencallconv" + of nkExprEqExpr: "vv" + of nkExprColonExpr: "kv" + of nkPar: "par" + of nkObjConstr: "oconstr" + of nkCurly: "curly" + of nkCurlyExpr: "curlyat" + of nkBracket: "bracket" + of nkBracketExpr: "at" + of nkPragmaBlock, nkPragmaExpr: "pragmax" + of nkDotExpr: "dot" + of nkAsgn, nkFastAsgn: "asgn" + of nkIfExpr, nkIfStmt: "if" + of nkWhenStmt, nkRecWhen: "when" + of nkWhileStmt: "while" + of nkCaseStmt, nkRecCase: "case" + of nkForStmt: "for" + of nkDiscardStmt: "discard" + of nkBreakStmt: "break" + of nkReturnStmt: "ret" + of nkElifExpr, nkElifBranch: "elif" + of nkElseExpr, nkElse: "else" + of nkOfBranch: "of" + of nkCast: "cast" + of nkLambda: "proc" + of nkAccQuoted: "quoted" + of nkTableConstr: "tabconstr" + of nkStmtListType, nkStmtListExpr, nkStmtList, nkRecList, nkArgList: "stmts" + of nkBlockStmt, nkBlockExpr, nkBlockType: "block" + of nkStaticStmt: "staticstmt" + of nkBind, nkBindStmt: "bind" + of nkMixinStmt: "mixin" + of nkAddr: "addr" + of nkGenericParams: "typevars" + of nkFormalParams: "params" + of nkImportAs: "importas" + of nkRaiseStmt: "raise" + of nkContinueStmt: "continue" + of nkYieldStmt: "yld" + of nkProcDef: "proc" + of nkFuncDef: "func" + of nkMethodDef: "method" + of nkConverterDef: "converter" + of nkMacroDef: "macro" + of nkTemplateDef: "template" + of nkIteratorDef: "iterator" + of nkExceptBranch: "except" + of nkTypeOfExpr: "typeof" + of nkFinally: "fin" + of nkTryStmt: "try" + of nkImportStmt: "import" + of nkImportExceptStmt: "importexcept" + of nkIncludeStmt: "include" + of nkExportStmt: "export" + of nkExportExceptStmt: "exportexcept" + of nkFromStmt: "fromimport" + of nkPragma: "pragmas" + of nkAsmStmt: "asm" + of nkDefer: "defer" + of nkUsingStmt: "using" + of nkCommentStmt: "comment" + of nkObjectTy: "object" + of nkTupleTy, nkTupleClassTy: "tuple" + of nkTypeClassTy: "concept" + of nkStaticTy: "static" + of nkRefTy: "ref" + of nkPtrTy: "ptr" + of nkVarTy: "mut" + of nkDistinctTy: "distinct" + of nkIteratorTy: "itertype" + of nkEnumTy: "enum" + #of nkEnumFieldDef: EnumFieldDecl + of nkTupleConstr: "tup" + of nkOutTy: "out" + of nkNone, nkEmpty, nkIdent, nkSym, nkType, nkCharLit, + nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit, + nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit, + nkFloatLit, nkFloat32Lit, nkFloat64Lit, nkFloat128Lit, + nkStrLit, nkRStrLit, nkTripleStrLit, nkNilLit: + # atoms special cased: + "err" + of nkDerefExpr: "deref" + of nkClosedSymChoice: "cchoice" + of nkOpenSymChoice: "ochoice" + of nkComesFrom, + nkDotCall, nkPostfix, nkIdentDefs, nkVarTuple, nkRange, nkCheckedFieldExpr, nkDo, + nkHiddenStdConv, nkHiddenSubConv, nkConv, nkStaticExpr, nkHiddenAddr, nkHiddenDeref, + nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange, + nkStringToCString, nkCStringToString, nkOfInherit, nkParForStmt, nkTypeSection, + nkVarSection, nkLetSection, nkConstSection, nkConstDef, nkTypeDef, nkWith, nkWithout, + nkConstTy, nkProcTy, nkSinkAsgn, nkEnumFieldDef, nkPattern, nkHiddenTryStmt, nkClosure, + nkGotoState, nkState, nkBreakState, nkError, nkModuleRef, nkReplayAction, nkNilRodNode, nkOpenSym: + "err" + +proc absLineInfo(i: TLineInfo; c: var TranslationContext) = + var fp = toFullPath(c.conf, i.fileIndex) + if c.portablePaths: + fp = relativePath(fp, getCurrentDir(), '/') + c.b.addLineInfo int32(i.col), int32(i.line), fp + +proc relLineInfo(n, parent: PNode; c: var TranslationContext; + emitSpace = false) = + if not c.lineInfoEnabled: return + let i = n.info + if parent == nil: + absLineInfo i, c + return + let p = parent.info + if i.fileIndex != p.fileIndex: + absLineInfo i, c + return + + let colDiff = int32(i.col) - int32(p.col) + let lineDiff = int32(i.line) - int32(p.line) + c.b.addLineInfo colDiff, lineDiff, "" + +proc addIntLit*(b: var Builder; u: BiggestInt; suffix: string) = + assert suffix.len > 0 + b.withTree "suf": + b.addIntLit u + b.addStrLit suffix + +proc addUIntLit*(b: var Builder; u: BiggestUInt; suffix: string) = + assert suffix.len > 0 + b.withTree "suf": + b.addUIntLit u + b.addStrLit suffix + +proc addFloatLit*(b: var Builder; u: BiggestFloat; suffix: string) = + assert suffix.len > 0 + b.withTree "suf": + b.addFloatLit u + b.addStrLit suffix + +type + IdentDefName = object + name, visibility, pragma: PNode + +proc splitIdentDefName(n: PNode): IdentDefName = + result = IdentDefName(visibility: nil, pragma: nil) + if n.kind == nkPragmaExpr: + result.pragma = n[1] + if n[0].kind == nkPostfix: + result.visibility = n[0][0] + result.name = n[0][1] + else: + result.name = n[0] + elif n.kind == nkPostfix: + result.visibility = n[0] + result.name = n[1] + else: + result.name = n + if n.kind == nkSym and sfExported in n.sym.flags: + result.visibility = n # anything other than `nil` will do here + +proc toNif(n, parent: PNode; c: var TranslationContext; allowEmpty = false) +proc toNifType(t: PType; parent: PNode; c: var TranslationContext) + +const + NewOperator = -2 + TypedMagic = -3 + TypedMagicOp1 = -4 + NoMagic = -5 + ArrayType = -6 + StringType = -7 + BecomesCall = -8 + +proc magicToNifTag(s: TMagic): (string, int) = + case s + of mNone: ("bug", NoMagic) + of mDefined: ("defined", 0) + of mDeclared: ("declared", 0) + of mDeclaredInScope: ("declaredinscope", NoMagic) + of mCompiles: ("compiles", 0) + of mArrGet: ("arrat", 0) + of mArrPut: ("arrat", 0) + of mAsgn: ("asgn", 0) + of mLow: ("low", 0) + of mHigh: ("high", 0) + of mSizeOf: ("sizeof", 0) + of mAlignOf: ("alignof", 0) + of mOffsetOf: ("offsetof", 0) + of mTypeTrait: ("typetrait", NoMagic) + of mIs: ("is", 0) + of mOf: ("instanceof", 0) + of mAddr: ("addr", 0) + of mType: ("typeof", 0) + of mTypeOf: ("typeof", 0) + of mPlugin: ("plugin", NoMagic) + of mEcho: ("echo", NoMagic) + of mShallowCopy: ("asgn", 0) + of mSlurp: ("slurp", NoMagic) + of mStaticExec: ("staticexec", NoMagic) + of mStatic: ("static", NoMagic) + of mParseExprToAst: ("parseexprtoast", NoMagic) + of mParseStmtToAst: ("parsestmttoast", NoMagic) + of mExpandToAst: ("expandtoast", NoMagic) + of mQuoteAst: ("quoteast", NoMagic) + of mInc: ("inc", NoMagic) + of mDec: ("dec", NoMagic) + of mOrd: ("ord", NoMagic) + of mNew: ("newref", NewOperator) + of mNewFinalize: ("newref", NewOperator) + of mNewSeq: ("newseq", NoMagic) + of mNewSeqOfCap: ("newseqofcap", NoMagic) + of mLengthOpenArray: ("lenopenarray", NoMagic) + of mLengthStr: ("lenstr", NoMagic) + of mLengthArray: ("lenarray", NoMagic) + of mLengthSeq: ("lenseq", NoMagic) + of mIncl: ("incl", 0) + of mExcl: ("excl", 0) + of mCard: ("card", TypedMagic) + of mChr: ("chr", NoMagic) + of mGCref: ("gcref", NoMagic) + of mGCunref: ("gcunref", NoMagic) + of mAddI: ("add", TypedMagic) + of mSubI: ("sub", TypedMagic) + of mMulI: ("mul", TypedMagic) + of mDivI: ("div", TypedMagic) + of mModI: ("mod", TypedMagic) + of mSucc: ("add", TypedMagic) + of mPred: ("sub", TypedMagic) + of mAddF64: ("add", TypedMagic) + of mSubF64: ("sub", TypedMagic) + of mMulF64: ("mul", TypedMagic) + of mDivF64: ("div", TypedMagic) + of mShrI: ("shr", TypedMagic) + of mShlI: ("shl", TypedMagic) + of mAshrI: ("ashr", TypedMagic) + of mBitandI: ("bitand", TypedMagic) + of mBitorI: ("bitor", TypedMagic) + of mBitxorI: ("bitxor", TypedMagic) + of mMinI: ("min", NoMagic) + of mMaxI: ("max", NoMagic) + of mAddU: ("add", TypedMagic) + of mSubU: ("sub", TypedMagic) + of mMulU: ("mul", TypedMagic) + of mDivU: ("div", TypedMagic) + of mModU: ("mod", TypedMagic) + of mEqI: ("eq", TypedMagicOp1) + of mLeI: ("le", TypedMagicOp1) + of mLtI: ("lt", TypedMagicOp1) + of mEqF64: ("eq", TypedMagicOp1) + of mLeF64: ("le", TypedMagicOp1) + of mLtF64: ("lt", TypedMagicOp1) + of mLeU: ("le", TypedMagicOp1) + of mLtU: ("lt", TypedMagicOp1) + of mEqEnum: ("eq", TypedMagicOp1) + of mLeEnum: ("le", TypedMagicOp1) + of mLtEnum: ("lt", TypedMagicOp1) + of mEqCh: ("eq", TypedMagicOp1) + of mLeCh: ("le", TypedMagicOp1) + of mLtCh: ("lt", TypedMagicOp1) + of mEqB: ("eq", TypedMagicOp1) + of mLeB: ("le", TypedMagicOp1) + of mLtB: ("lt", TypedMagicOp1) + of mEqRef: ("eq", TypedMagicOp1) + of mLePtr: ("le", TypedMagicOp1) + of mLtPtr: ("lt", TypedMagicOp1) + of mXor: ("xor", 0) + of mEqCString: ("eq", NoMagic) + of mEqProc: ("eq", TypedMagicOp1) + of mUnaryMinusI: ("neg", 0) + of mUnaryMinusI64: ("neg", 0) + of mAbsI: ("abs", NoMagic) + of mNot: ("not", 0) + of mUnaryPlusI: ("unaryplus", NoMagic) + of mBitnotI: ("bitnot", TypedMagic) + of mUnaryPlusF64: ("unaryplusf64", NoMagic) + of mUnaryMinusF64: ("neg", 0) + of mCharToStr: ("chartostr", NoMagic) + of mBoolToStr: ("booltostr", NoMagic) + of mCStrToStr: ("fromCString.0." & SystemModuleSuffix, BecomesCall) + of mStrToStr: ("strtostr", NoMagic) + of mEnumToStr: ("enumtostr", 0) + of mAnd: ("and", 0) + of mOr: ("or", 0) + of mImplies: ("implies", NoMagic) + of mIff: ("iff", NoMagic) + of mExists: ("exists", NoMagic) + of mForall: ("forall", NoMagic) + of mOld: ("old", NoMagic) + of mEqStr: ("==.15." & SystemModuleSuffix, BecomesCall) # XXX find a better solution + of mLeStr: ("<=.15." & SystemModuleSuffix, BecomesCall) + of mLtStr: ("<.15." & SystemModuleSuffix, BecomesCall) + of mEqSet: ("eqset", TypedMagicOp1) + of mLeSet: ("leset", TypedMagicOp1) + of mLtSet: ("ltset", TypedMagicOp1) + of mMulSet: ("mulset", TypedMagic) + of mPlusSet: ("plusset", TypedMagic) + of mMinusSet: ("minusset", TypedMagic) + of mXorSet: ("xorset", TypedMagic) + of mConStrStr: ("&.0." & SystemModuleSuffix, BecomesCall) + of mSlice: ("slice", NoMagic) + of mDotDot: ("dotdot", NoMagic) + of mFields: ("fields", 0) + of mFieldPairs: ("fieldpairs", 0) + of mOmpParFor: ("ompparfor", NoMagic) + of mAppendStrCh: ("addstrch", NoMagic) + of mAppendStrStr: ("addstrstr", NoMagic) + of mAppendSeqElem: ("addseqelem", NoMagic) + of mInSet: ("inset", TypedMagicOp1) + of mRepr: ("repr", NoMagic) + of mExit: ("exit", NoMagic) + of mSetLengthStr: ("setlenstr", NoMagic) + of mSetLengthSeq: ("setlenseq", NoMagic) + of mIsPartOf: ("ispartof", NoMagic) + of mAstToStr: ("asttostr", NoMagic) + of mParallel: ("parallel", NoMagic) + of mSwap: ("swap", NoMagic) + of mIsNil: ("isnil", NoMagic) + of mArrToSeq: ("arrtoseq", NoMagic) + of mOpenArrayToSeq: ("openarraytoseq", NoMagic) + of mNewString: ("newString.0." & SystemModuleSuffix, BecomesCall) + of mNewStringOfCap: ("newStringOfCap.0." & SystemModuleSuffix, BecomesCall) + of mParseBiggestFloat: ("parsebiggestfloat", NoMagic) + of mMove: ("move", NoMagic) + of mEnsureMove: ("emove", 0) + of mWasMoved: ("wasmoved", 0) + of mDup: ("dup", 0) + of mDestroy: ("destroy", 0) + of mTrace: ("trace", 0) + of mDefault: ("defaultobj", NoMagic) + of mUnown: ("unown", NoMagic) + of mFinished: ("finished", NoMagic) + of mIsolate: ("isolate", NoMagic) + of mAccessEnv: ("accessenv", NoMagic) + of mAccessTypeField: ("accesstypefield", NoMagic) + of mArray: ("array", ArrayType) + of mOpenArray: ("flexarray", NoMagic) + of mRange: ("range", NoMagic) + of mSet: ("set", 0) + of mSeq: ("seq", NoMagic) + of mVarargs: ("varargs", 0) + of mRef: ("ref", 0) + of mPtr: ("ptr", 0) + of mVar: ("mut", 0) + of mDistinct: ("distinct", 0) + of mVoid: ("void", 0) + of mTuple: ("tuple", 0) + of mOrdinal: ("ordinal", NoMagic) + of mIterableType: ("iterabletype", NoMagic) + of mInt: ("i", -1) + of mInt8: ("i", 8) + of mInt16: ("i", 16) + of mInt32: ("i", 32) + of mInt64: ("i", 64) + of mUInt: ("u", -1) + of mUInt8: ("u", 8) + of mUInt16: ("u", 16) + of mUInt32: ("u", 32) + of mUInt64: ("u", 64) + of mFloat: ("f", 64) + of mFloat32: ("f", 32) + of mFloat64: ("f", 64) + of mFloat128: ("f", 128) + of mBool: ("bool", 0) + of mChar: ("c", 8) + of mString: ("string", StringType) + of mCstring: ("cstring", 0) + of mPointer: ("pointer", 0) + of mNil: ("nil", 0) + of mExpr: ("expr", NoMagic) + of mStmt: ("stmt", NoMagic) + of mTypeDesc: ("typedesc", 0) + of mVoidType: ("void", 0) + of mPNimrodNode: ("nimnode", NoMagic) + of mSpawn: ("spawn", NoMagic) + of mDeepCopy: ("deepcopy", NoMagic) + of mIsMainModule: ("ismainmodule", 0) + of mCompileDate: ("compiledate", NoMagic) + of mCompileTime: ("compiletime", NoMagic) + of mProcCall: ("proccall", 0) + of mCpuEndian: ("cpuendian", NoMagic) + of mHostOS: ("hostos", NoMagic) + of mHostCPU: ("hostcpu", NoMagic) + of mBuildOS: ("buildos", NoMagic) + of mBuildCPU: ("buildcpu", NoMagic) + of mAppType: ("apptype", NoMagic) + of mCompileOption: ("compileoption", NoMagic) + of mCompileOptionArg: ("compileoptionarg", NoMagic) + of mNLen: ("nlen", NoMagic) + of mNChild: ("nchild", NoMagic) + of mNSetChild: ("nsetchild", NoMagic) + of mNAdd: ("nadd", NoMagic) + of mNAddMultiple: ("naddmultiple", NoMagic) + of mNDel: ("ndel", NoMagic) + of mNKind: ("nkind", NoMagic) + of mNSymKind: ("nsymkind", NoMagic) + of mNccValue: ("nccvalue", NoMagic) + of mNccInc: ("nccinc", NoMagic) + of mNcsAdd: ("ncsadd", NoMagic) + of mNcsIncl: ("ncsincl", NoMagic) + of mNcsLen: ("ncslen", NoMagic) + of mNcsAt: ("ncsat", NoMagic) + of mNctPut: ("nctput", NoMagic) + of mNctLen: ("nctlen", NoMagic) + of mNctGet: ("nctget", NoMagic) + of mNctHasNext: ("ncthasnext", NoMagic) + of mNctNext: ("nctnext", NoMagic) + of mNIntVal: ("nintval", NoMagic) + of mNFloatVal: ("nfloatval", NoMagic) + of mNSymbol: ("nsymbol", NoMagic) + of mNIdent: ("nident", NoMagic) + of mNGetType: ("ngettype", NoMagic) + of mNStrVal: ("nstrval", NoMagic) + of mNSetIntVal: ("nsetintval", NoMagic) + of mNSetFloatVal: ("nsetfloatval", NoMagic) + of mNSetSymbol: ("nsetsymbol", NoMagic) + of mNSetIdent: ("nsetident", NoMagic) + of mNSetStrVal: ("nsetstrval", NoMagic) + of mNLineInfo: ("nlineinfo", NoMagic) + of mNNewNimNode: ("nnewnimnode", NoMagic) + of mNCopyNimNode: ("ncopynimnode", NoMagic) + of mNCopyNimTree: ("ncopynimtree", NoMagic) + of mStrToIdent: ("strtoident", NoMagic) + of mNSigHash: ("nsighash", NoMagic) + of mNSizeOf: ("nsizeof", NoMagic) + of mNBindSym: ("nbindsym", NoMagic) + of mNCallSite: ("ncallsite", NoMagic) + of mEqIdent: ("eqident", NoMagic) + of mEqNimrodNode: ("eqnimnode", NoMagic) + of mSameNodeType: ("samenodetype", NoMagic) + of mGetImpl: ("getimpl", NoMagic) + of mNGenSym: ("ngensym", NoMagic) + of mNHint: ("nhint", NoMagic) + of mNWarning: ("nwarning", NoMagic) + of mNError: ("nerror", NoMagic) + of mInstantiationInfo: ("instantiationinfo", NoMagic) + of mGetTypeInfo: ("gettypeinfo", NoMagic) + of mGetTypeInfoV2: ("gettypeinfov2", NoMagic) + of mNimvm: ("nimvm", NoMagic) + of mIntDefine: ("intdefine", NoMagic) + of mStrDefine: ("strdefine", NoMagic) + of mBoolDefine: ("booldefine", NoMagic) + of mGenericDefine: ("genericdefine", NoMagic) + of mRunnableExamples: ("runnableexamples", NoMagic) + of mException: ("exception", NoMagic) + of mBuiltinType: ("builtintype", NoMagic) + of mSymOwner: ("symowner", NoMagic) + of mUncheckedArray: ("uarray", 0) + of mGetImplTransf: ("getimpltransf", NoMagic) + of mSymIsInstantiationOf: ("symisinstantiationof", NoMagic) + of mNodeId: ("nodeid", NoMagic) + of mPrivateAccess: ("privateaccess", NoMagic) + of mZeroDefault: ("zerodefault", NoMagic) + +proc modname(c: var TranslationContext; idx: FileIndex): string = + result = c.toSuffix.getOrDefault(idx) + if result.len == 0: + let fp = toFullPath(c.conf, idx) + result = moduleSuffix(fp, cast[seq[string]](c.conf.searchPaths)) + c.toSuffix[idx] = result + +proc symToNif(orig: PSym; parent: PNode; c: var TranslationContext; isDef = false) = + # We do not want to use generic instantiations as the names! We instead want + # Nimony to re-instantiate the generic symbol: + let isInstantiated = orig.kind in skProcKinds and sfFromGeneric in orig.flags + let s = if isInstantiated: orig.owner else: orig + # Unfortunately, this is not enough. Code like `myGeneric[int, char]()` will + # have lost the explicit type parameters. We can get these from the instance cache. + + var m = s.name.s & '.' & $s.disamb + var ow = if orig.kind in {skField, skEnumField}: s.originatingModule() else: s.skipGenericOwner() + if ow == nil: + ow = c.graph.systemModule # can happen for magics created by the createMagic + if ow.kind == skModule: + m.add '.' + m.add modname(c, FileIndex ow.position) + if isDef: + c.b.addSymbolDef m + elif isInstantiated: + c.b.addTree "at" + c.b.addSymbol m + for inst in procInstCacheItems(c.graph, s): + if inst.sym == orig: + # for terrible reasons `concreteTypes` contains all the types, + # so we need to know how many generic params there were: + for i in 0..= -1: + c.b.addTree tag + if bits != 0: + c.b.addIntLit bits + c.b.endTree() + else: + c.b.addSymbol m + else: + c.b.addSymbol m + +proc toNifDecl(n, parent: PNode; c: var TranslationContext) = + if n.kind == nkSym: + relLineInfo(n, parent, c) + symToNif(n.sym, parent, c, true) + else: + toNif n, parent, c + +proc toVarTuple(v: PNode, n: PNode; c: var TranslationContext) = + c.b.addTree("unpacktup") + for i in 0.. 3: + # multiple ident defs, we need to add StmtsL + c.b.addTree("stmts") + toNif(n, parent, c) + c.b.endTree() + else: + toNif(n, parent, c) + +template writeTypeFlags(c: var TranslationContext; t: PType) = + discard "maybe we need type flags later" + +proc isNominalRef(t: PType): bool {.inline.} = + if t.hasElementType: + let e = t.elementType + t.sym != nil and e.kind == tyObject and (e.sym == nil or sfAnon in e.sym.flags) + else: + false + +template singleElement(keyw: string) {.dirty.} = + c.b.withTree keyw: + writeTypeFlags(c, t) + if t.hasElementType: + toNifType t.elementType, parent, c + else: + c.b.addEmpty + +proc atom(t: PType; c: var TranslationContext; tag: string) = + c.b.withTree tag: + writeTypeFlags(c, t) + +proc toNifTag(s: TTypeKind): string = + case s + of tyNone: "none" + of tyBool: "bool" + of tyChar: "c" + of tyEmpty: "empty" + of tyAlias: "alias" + of tyNil: "nil" + of tyUntyped: "untyped" + of tyTyped: "typed" + of tyTypeDesc: "typedesc" + of tyGenericInvocation: "at" + of tyGenericBody: "gbody" + of tyGenericInst: "at" + of tyGenericParam: "gparam" + of tyDistinct: "distinct" + of tyEnum: "enum" + of tyOrdinal: "ordinal" + of tyArray: "array" + of tyObject: "object" + of tyTuple: "tuple" + of tySet: "set" + of tyRange: "range" + of tyPtr: "ptr" + of tyRef: "ref" + of tyVar: "mut" + of tySequence: "seq" + of tyProc: "proctype" + of tyPointer: "pointer" + of tyOpenArray: "openArray" + of tyString: "string" + of tyCstring: "cstring" + of tyForward: "forward" + of tyInt: "int" + of tyInt8: "int8" + of tyInt16: "int16" + of tyInt32: "int32" + of tyInt64: "int64" + of tyFloat: "float" + of tyFloat32: "float32" + of tyFloat64: "float64" + of tyFloat128: "float128" + of tyUInt: "uint" + of tyUInt8: "uint8" + of tyUInt16: "uint16" + of tyUInt32: "uint32" + of tyUInt64: "uint64" + of tyOwned: "owned" + of tySink: "sink" + of tyLent: "lent" + of tyVarargs: "varargs" + of tyUncheckedArray: "uarray" + of tyError: "error" + of tyBuiltInTypeClass: "bconcept" + of tyUserTypeClass: "uconcept" + of tyUserTypeClassInst: "uconceptinst" + of tyCompositeTypeClass: "cconcept" + of tyInferred: "inferred" + of tyAnd: "and" + of tyOr: "or" + of tyNot: "not" + of tyAnything: "anything" + of tyStatic: "static" + of tyFromExpr: "typeof" + of tyConcept: "concept" + of tyVoid: "void" + of tyIterable: "iterable" + +proc atom(t: PType; c: var TranslationContext) = + c.b.withTree toNifTag(t.kind): + writeTypeFlags(c, t) + +template typeHead(c: var TranslationContext; t: PType; body: untyped) = + c.b.withTree toNifTag(t.kind): + writeTypeFlags(c, t) + body + +proc toNifTag(s: TCallingConvention): string = + case s + of ccNimCall: "nimcall" + of ccStdCall: "stdcall" + of ccCDecl: "cdecl" + of ccSafeCall: "safecall" + of ccSysCall: "syscall" + of ccInline: "inline" + of ccNoInline: "noinline" + of ccFastCall: "fastcall" + of ccThisCall: "thiscall" + of ccClosure: "closure" + of ccNoConvention: "noconv" + of ccMember: "member" + +proc symbolType(name: string; t: PType; c: var TranslationContext) = + c.b.addSymbol name + +proc genericAt(name: string; parent: PNode; t: PType; c: var TranslationContext) = + c.b.withTree "at": + c.b.addSymbol name + for _, son in t.ikids: toNifType son, parent, c + +proc toNifType(t: PType; parent: PNode; c: var TranslationContext) = + if t == nil: + c.b.addKeyw "nil" + return + + case t.kind + of tyNone: atom t, c + of tyBool: atom t, c + of tyChar: atom t, c, "c 8" + of tyEmpty: c.b.addEmpty + of tyInt: atom t, c, "i -1" + of tyInt8: atom t, c, "i 8" + of tyInt16: atom t, c, "i 16" + of tyInt32: atom t, c, "i 32" + of tyInt64: atom t, c, "i 64" + of tyUInt: atom t, c, "u -1" + of tyUInt8: atom t, c, "u 8" + of tyUInt16: atom t, c, "u 16" + of tyUInt32: atom t, c, "u 32" + of tyUInt64: atom t, c, "u 64" + of tyFloat, tyFloat64: atom t, c, "f 64" + of tyFloat32: atom t, c, "f 32" + of tyFloat128: atom t, c, "f 128" + of tyAlias: + c.typeHead t: + toNifType t.skipModifier, parent, c + of tyNil: atom t, c + of tyUntyped: atom t, c + of tyTyped: atom t, c + of tyTypeDesc: + c.typeHead t: + if t.kidsLen == 0 or t.elementType.kind == tyNone: + c.b.addEmpty + else: + toNifType t.elementType, parent, c + of tyGenericParam: + if t.sym != nil: + symToNif t.sym, parent, c + else: + c.typeHead t: + discard + + of tyGenericInst: + c.typeHead t: + toNifType t.genericHead, parent, c + for _, a in t.genericInstParams: + toNifType a, parent, c + of tyGenericInvocation: + c.typeHead t: + toNifType t.genericHead, parent, c + for _, a in t.genericInvocationParams: + toNifType a, parent, c + of tyGenericBody: + #toNifType t.last, parent, c + c.typeHead t: + for _, son in t.ikids: toNifType son, parent, c + of tyDistinct, tyEnum: + if t.sym != nil: + symToNif t.sym, parent, c + else: + c.typeHead t: + for _, son in t.ikids: toNifType son, parent, c + of tyPtr: + if isNominalRef(t): + symToNif t.sym, parent, c + else: + c.typeHead t: + if t.hasElementType: + toNifType t.elementType, parent, c + else: + c.b.addEmpty + of tyRef: + if isNominalRef(t): + symToNif t.sym, parent, c + else: + c.typeHead t: + if t.hasElementType: + toNifType t.elementType, parent, c + else: + c.b.addEmpty + of tyVar: + c.b.withTree(if isOutParam(t): "out" else: "mut"): + toNifType t.elementType, parent, c + of tyAnd: + c.typeHead t: + for _, son in t.ikids: toNifType son, parent, c + of tyOr: + c.typeHead t: + for _, son in t.ikids: toNifType son, parent, c + of tyNot: + c.typeHead t: toNifType t.elementType, parent, c + + of tyFromExpr: + if t.n == nil: + atom t, c, "err" + else: + c.typeHead t: + toNif t.n, parent, c + + of tyArray: + c.typeHead t: + if t.hasElementType: + toNifType t.elementType, parent, c + toNifType t.indexType, parent, c + else: + c.b.addEmpty 2 + of tyUncheckedArray: + c.typeHead t: + if t.hasElementType: + toNifType t.elementType, parent, c + else: + c.b.addEmpty + + of tySequence: + genericAt "seq.0." & SystemModuleSuffix, parent, t, c + + of tyOrdinal: + c.typeHead t: + if t.hasElementType: + toNifType t.skipModifier, parent, c + else: + c.b.addEmpty + + of tySet: singleElement toNifTag(t.kind) + of tyOpenArray: genericAt "openArray.0." & SystemModuleSuffix, parent, t, c + of tyIterable: singleElement toNifTag(t.kind) + of tyLent: singleElement toNifTag(t.kind) + + of tyTuple: + c.typeHead t: + if t.n != nil: + for i in 0.. 0: + # generic constraints: + toNifType t[0], n, c + else: + c.b.addEmpty + c.b.addEmpty # value + c.b.endTree() + else: + toNif n, parent, c + +proc addExternName(sym: PSym; c: var TranslationContext) = + if sym.loc.snippet != nil: + c.b.addStrLit sym.loc.snippet + else: + c.b.addStrLit sym.name.s + +proc takePragmasFromSym(sym: PSym; parent: PNode; c: var TranslationContext) = + if sfImportc in sym.flags: + c.b.withTree "importc": + addExternName(sym, c) + elif sfExportc in sym.flags: + c.b.withTree "exportc": + addExternName(sym, c) + if sfCursor in sym.flags: + c.b.addKeyw "cursor" + if sfNoInit in sym.flags: + c.b.addKeyw "noinit" + if lfNoDecl in sym.loc.flags: + c.b.addKeyw "nodecl" + if sfNoReturn in sym.flags: + c.b.addKeyw "noreturn" + if sym.typ != nil: + let t = sym.typ + if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: + discard "no calling convention to generate" + else: + c.b.addKeyw toNifTag(t.callConv) + + # XXX Add more pragmas here + var isUntyped = false + if sym.kind in routineKinds and sym.ast != nil and sym.ast[genericParamsPos].kind == nkGenericParams: + isUntyped = true + elif sym.kind == skTemplate: + isUntyped = true + if isUntyped: + c.b.addKeyw "untyped" + +proc toNifPragmas(n: PNode; parent: PNode; c: var TranslationContext; name: PNode) = + if n == nil: + if name.kind == nkSym: + c.b.withTree "pragmas": + takePragmasFromSym(name.sym, parent, c) + else: + c.b.addEmpty + else: + c.b.withTree "pragmas": + for child in n: + toNif child, n, c + if name.kind == nkSym: + takePragmasFromSym(name.sym, parent, c) + +proc toNifProcBody(n: PNode; parent: PNode; c: var TranslationContext; name: PNode) = + if n.kind == nkEmpty: + c.b.addEmpty + else: + c.b.withTree "stmts": + #if name.kind == nkSym and name.sym.kind notin {skTemplate, skIterator} and name.sym.typ != nil and + var ast = parent + if name.kind == nkSym and name.sym.ast != nil: + ast = name.sym.ast + var resultSym = PSym(nil) + if resultPos < ast.len and ast[resultPos].kind == nkSym: + resultSym = ast[resultPos].sym + c.b.withTree "result": + toNifDecl(ast[resultPos], parent, c) + c.b.addEmpty # export marker + if name.kind == nkSym and sfNoInit in name.sym.flags: + c.b.withTree "pragmas": + c.b.addKeyw "noinit" + else: + c.b.addEmpty # pragmas + toNifType resultSym.typ, parent, c + c.b.addEmpty # value + var endsInReturn = false + if n.kind == nkStmtList: + for child in n: + toNif child, n, c + endsInReturn = child.kind == nkReturnStmt + else: + endsInReturn = n.kind == nkReturnStmt + toNif n, parent, c + if not endsInReturn and resultSym != nil: + c.b.withTree "ret": + symToNif resultSym, parent, c + +proc toNif(n, parent: PNode; c: var TranslationContext; allowEmpty = false) = + case n.kind + of nkSym: + symToNif(n.sym, parent, c) + of nkNone: + assert false, "unexpected nkNone" + of nkEmpty: + #assert allowEmpty, "unexpected nkEmpty" + c.b.addEmpty 1 + of nkNilLit: + relLineInfo(n, parent, c) + c.b.addRaw "(nil)" + of nkStrLit: + relLineInfo(n, parent, c) + c.b.addStrLit n.strVal + of nkRStrLit: + relLineInfo(n, parent, c) + c.b.addStrLit n.strVal, "R" + of nkTripleStrLit: + relLineInfo(n, parent, c) + c.b.addStrLit n.strVal, "T" + of nkCharLit: + relLineInfo(n, parent, c) + c.b.addCharLit char(n.intVal) + of nkIntLit: + relLineInfo(n, parent, c, true) + c.b.addIntLit n.intVal + of nkInt8Lit: + relLineInfo(n, parent, c, true) + c.b.addIntLit n.intVal, "i8" + of nkInt16Lit: + relLineInfo(n, parent, c, true) + c.b.addIntLit n.intVal, "i16" + of nkInt32Lit: + relLineInfo(n, parent, c, true) + c.b.addIntLit n.intVal, "i32" + of nkInt64Lit: + relLineInfo(n, parent, c, true) + c.b.addIntLit n.intVal, "i64" + of nkUIntLit: + relLineInfo(n, parent, c, true) + c.b.addUIntLit cast[BiggestUInt](n.intVal) + of nkUInt8Lit: + relLineInfo(n, parent, c, true) + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u8" + of nkUInt16Lit: + relLineInfo(n, parent, c, true) + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u16" + of nkUInt32Lit: + relLineInfo(n, parent, c, true) + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u32" + of nkUInt64Lit: + relLineInfo(n, parent, c, true) + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u64" + of nkFloatLit: + relLineInfo(n, parent, c, true) + c.b.addFloatLit n.floatVal + of nkFloat32Lit: + relLineInfo(n, parent, c, true) + c.b.addFloatLit n.floatVal, "f32" + of nkFloat64Lit: + relLineInfo(n, parent, c, true) + c.b.addFloatLit n.floatVal, "f64" + of nkFloat128Lit: + relLineInfo(n, parent, c, true) + c.b.addFloatLit n.floatVal, "f128" + of nkIdent: + relLineInfo(n, parent, c, true) + c.b.addIdent n.ident.s + of nkTypeDef: + relLineInfo(n, parent, c) + c.b.addTree "type" + let split = splitIdentDefName(n[0]) + + toNifDecl(split.name, n, c) + + if split.visibility != nil: + c.b.addRaw " x" + else: + c.b.addEmpty + + toNif(n[1], n, c, allowEmpty = true) # generics + + if split.pragma != nil: + toNif(split.pragma, n, c) + else: + c.b.addEmpty + + let oldHasHoles = c.hasHoles + c.hasHoles = split.name.kind == nkSym and split.name.sym.typ != nil and + tfEnumHasHoles in split.name.sym.typ.flags + for i in 2.. 0: + toNif(n[n.len-1], n, c) + else: + c.b.addEmpty + c.b.endTree() + + of nkProcTy, nkIteratorTy: + relLineInfo(n, parent, c) + if n.kind == nkProcTy: + c.b.addTree("proctype") + else: + c.b.addTree("itertype") + + c.b.addEmpty 4 # 0: name + # 1: export marker + # 2: pattern + # 3: generics + + if n.len > 0: + toNif n[0], n, c, allowEmpty = true # 4: params + else: + c.b.addEmpty + + if n.len > 1: + toNif n[1], n, c, allowEmpty = true # 5: pragmas + else: + c.b.addEmpty + + c.b.addEmpty 2 # 6: exceptions + # 7: body + c.b.endTree() + + of nkEnumTy: + # EnumField + # SymDef "x" + # Empty # export marker (always empty) + # Empty # pragmas + # EnumType + # (Integer value, "string value") + relLineInfo(n, parent, c) + if n.len == 0: + # typeclass, compiles to identifier for nimony + c.b.addIdent "enum" + else: + if c.hasHoles: + c.b.addTree("onum") + else: + c.b.addTree("enum") + assert n[0].kind == nkEmpty + c.b.addEmpty # base type + for i in 1.. 0 and n[0].kind == nkIdent and n[0].ident.s == "runnableExamples": + c.depsEnabled = false + relLineInfo(n, parent, c) + if n.len > 0 and n[0].kind == nkSym and n[0].sym.magic != mNone: + magicCall n[0].sym.magic, n, c + else: + c.b.addTree(nodeKindTranslation(n.kind)) + for i in 0.. 0 and n[0].kind == nkEmpty: + toNifType(n.typ, n, c) + start = 1 + for i in start..