# # # 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 outfile: string 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 mSetLengthSeqUninit: ("setlensequninit", 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 projectHash(c: var TranslationContext): string = result = moduleSuffix(c.conf.projectFull.string, []) 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 in {nkAsgn, nkFastAsgn}: toNif(n[0][1], n, c) else: for i in 0.. 0 and n[0].kind == nkEmpty: toNifType(n.typ, n, c) start = 1 for i in start..