Files
Nim/compiler/nifgen.nim
ringabout 611b8bbf67 fixes #25007; implements setLenUninit for refc (#25022)
fixes #25007

```nim
proc setLengthSeqUninit(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
    compilerRtl.} =
```

In this added function, only the line `zeroMem(dataPointer(result,
elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)` is
removed from `proc setLengthSeqV2` when enlarging a sequence.

JS and VM versions simply use `setLen`.
2025-07-14 23:19:58 +02:00

1691 lines
48 KiB
Nim

#
#
# 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..<inst.genericParamsCount:
toNifType(inst.concreteTypes[i], parent, c)
break
c.b.endTree()
elif s.kind == skType and sfImportc notin s.flags and s.magic != mNone:
let (tag, bits) = magicToNifTag(s.magic)
if bits >= -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..<v.len-1: # ignores typedesc
c.b.addTree("let")
toNifDecl(v[i], n, c) # name
c.b.addEmpty 4 # export marker, pragmas, type, value
c.b.endTree() # LetDecl
c.b.endTree() # UnpackIntoTuple
proc handleCaseIdentDefs(n, parent: PNode; c: var TranslationContext) =
if n.kind == nkIdentDefs and n.len > 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..<t.n.len:
assert(t.n[i].kind == nkSym)
c.b.withTree "kv":
c.b.addIdent t.n[i].sym.name.s
toNifType t.n[i].sym.typ, parent, c
else:
for _, son in t.ikids: toNifType son, parent, c
of tyRange:
c.typeHead t:
toNifType t.elementType, parent, c
if t.n != nil and t.n.kind == nkRange and t.n.len == 2:
toNif t.n[0], parent, c
toNif t.n[1], parent, c
else:
c.b.addEmpty 2
of tyProc:
let kind = if tfIterator in t.flags: "iteratortype"
else: "proctype"
c.b.withTree kind:
c.b.addEmpty # name
for i, a in t.paramTypes:
let j = paramTypeToNodeIndex(i)
if t.n != nil and j < t.n.len and t.n[j].kind == nkSym:
c.b.addIdent(t.n[j].sym.name.s)
toNifType a, parent, c
if tfUnresolved in t.flags:
c.b.addRaw "[*missing parameters*]"
if t.hasElementType and t.returnType != nil:
toNifType t.returnType, parent, c
else:
c.b.addEmpty
c.b.withTree "effects":
# XXX model explicit .raises and .tags annotations
if tfNoSideEffect in t.flags:
c.b.addKeyw "noside"
if tfThread in t.flags:
c.b.addKeyw "gcsafe"
c.b.withTree "pragmas":
if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags:
discard "no calling convention to generate"
else:
c.b.addKeyw toNifTag(t.callConv)
of tyVarargs:
c.typeHead t:
if t.hasElementType:
toNifType t.elementType, parent, c
else:
c.b.addEmpty
if t.n != nil:
toNif t.n, parent, c
else:
c.b.addEmpty
of tySink: singleElement toNifTag(t.kind)
of tyOwned: singleElement toNifTag(t.kind)
of tyVoid: atom t, c
of tyPointer: atom t, c
of tyString: symbolType "string.0." & SystemModuleSuffix, t, c
of tyCstring: atom t, c
of tyObject:
if t.sym != nil:
symToNif t.sym, parent, c
else:
c.b.addEmpty
of tyForward: atom t, c
of tyError: atom t, c
of tyBuiltInTypeClass:
# XXX See what to do with this.
c.typeHead t:
if t.kidsLen == 0 or t.genericHead.kind == tyNone:
c.b.addEmpty
else:
toNifType t.genericHead, parent, c
of tyUserTypeClass, tyConcept:
# ^ old style concept. ^ new style concept.
if t.sym != nil:
symToNif t.sym, parent, c
else:
atom t, c, "err"
of tyUserTypeClassInst:
# "instantiated" old style concept. Whatever that even means.
if t.sym != nil:
symToNif t.sym, parent, c
else:
atom t, c, "err"
of tyCompositeTypeClass: toNifType t.last, parent, c
of tyInferred: toNifType t.skipModifier, parent, c
of tyAnything: atom t, c
of tyStatic:
c.typeHead t:
if t.hasElementType:
toNifType t.skipModifier, parent, c
else:
c.b.addEmpty
if t.n != nil:
toNif t.n, parent, c
else:
c.b.addEmpty
proc magicCall(m: TMagic; n: PNode; c: var TranslationContext) =
let (tag, bits) = magicToNifTag(m)
if bits == NoMagic:
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
elif bits == ArrayType and n.len == 2:
c.b.addTree(tag)
# reverse order:
toNif n[1], n, c
toNif n[0], n, c
c.b.endTree()
elif bits == BecomesCall:
c.b.addTree("call")
c.b.addSymbol(tag)
for i in 1..<n.len:
toNif(n[i], n, c)
c.b.endTree()
else:
c.b.addTree(tag)
if bits == TypedMagic:
toNifType n.typ, n, c
elif bits == TypedMagicOp1:
toNifType n[1].typ, n, c
for i in 1..<n.len:
toNif(n[i], n, c)
c.b.endTree()
proc genericParamToNif(n: PNode; parent: PNode; c: var TranslationContext) =
if n.kind == nkSym:
c.b.addTree("typevar")
toNifDecl n, parent, c
c.b.addEmpty # export
c.b.addEmpty # pragmas
let t = n.sym.typ
if t != nil and t.len > 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..<n.len:
toNif(n[i], n, c, allowEmpty = true)
c.hasHoles = oldHasHoles
c.b.endTree()
of nkTypeSection:
for i in 0..<n.len:
toNif(n[i], parent, c)
of nkVarSection:
c.section = VarL
for i in 0..<n.len:
toNif(n[i], parent, c)
of nkLetSection:
c.section = LetL
for i in 0..<n.len:
toNif(n[i], parent, c)
of nkConstSection:
c.section = ConstL
for i in 0..<n.len:
toNif(n[i], parent, c)
of nkFormalParams:
c.section = ParamL
relLineInfo(n, parent, c)
c.b.addTree("params")
for i in 1..<n.len:
toNif(n[i], n, c)
c.b.endTree()
# put return type outside of `(params)`:
toNif(n[0], n, c, allowEmpty = true)
of nkGenericParams:
c.section = TypevarL
relLineInfo(n, parent, c)
c.b.addTree("typevars")
for i in 0..<n.len:
genericParamToNif(n[i], n, c)
c.b.endTree()
of nkIdentDefs, nkConstDef:
# multiple ident defs are annoying so we remove them here:
assert c.section != NiflerKind.None
let last = n.len-1
for i in 0..last - 2:
relLineInfo(n[i], parent, c)
c.b.addTree($c.section)
# flatten it further:
let split = splitIdentDefName(n[i])
toNifDecl(split.name, n[i], c) # name
if split.visibility != nil:
c.b.addRaw " x"
else:
c.b.addEmpty
toNifPragmas(split.pragma, n[i], c, split.name)
if split.name.kind == nkSym and split.name.sym.typ != nil:
toNifType split.name.sym.typ, n[i], c
else:
toNif(n[last-1], n[i], c, allowEmpty = true) # type
toNif(n[last], n[i], c, allowEmpty = true) # value
c.b.endTree()
of nkDo:
relLineInfo(n, parent, c)
c.b.addTree("do")
toNif(n[paramsPos], n, c, allowEmpty = true)
toNif(n[bodyPos], n, c)
c.b.endTree()
of nkOfInherit:
if n.len == 1:
toNif(n[0], parent, c)
else:
relLineInfo(n, parent, c)
c.b.addTree("par")
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkOfBranch:
relLineInfo(n, parent, c)
c.b.addTree("of")
c.b.addTree("ranges")
for i in 0..<n.len-1:
toNif(n[i], n, c)
c.b.endTree()
handleCaseIdentDefs(n[n.len-1], n, c)
c.b.endTree()
of nkElse:
relLineInfo(n, parent, c)
c.b.addTree("else")
handleCaseIdentDefs(n[n.len-1], n, c)
c.b.endTree()
of nkStmtListType, nkStmtListExpr:
relLineInfo(n, parent, c)
c.b.addTree("expr")
c.b.addTree("stmts")
for i in 0..<n.len-1:
toNif(n[i], n, c)
c.b.endTree()
if n.len > 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..<n.len:
let it = n[i]
var name: PNode
var val: PNode
var pragma: PNode
if it.kind == nkEnumFieldDef:
let first = it[0]
if first.kind == nkPragmaExpr:
name = first[0]
pragma = first[1]
else:
name = it[0]
pragma = nil
val = it[1]
elif it.kind == nkPragmaExpr:
name = it[0]
pragma = it[1]
val = nil
else:
name = it
pragma = nil
val = nil
relLineInfo(it, n, c)
c.b.addTree("efld")
toNifDecl name, it, c
c.b.addEmpty # export marker
toNifPragmas(pragma, it, c, name)
c.b.addEmpty # type (filled by sema)
if val == nil:
c.b.addEmpty
else:
toNif(val, it, c)
c.b.endTree()
c.b.endTree()
of nkProcDef, nkFuncDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkMethodDef:
var name: PNode
var visibility: PNode = nil
if n[0].kind == nkPostfix:
visibility = n[0][0]
name = n[0][1]
else:
name = n[0]
if name.kind == nkSym and sfExported in name.sym.flags:
visibility = name # anything other than nil will do
if name.kind == nkSym and
({sfForward, sfFromGeneric} * name.sym.flags != {} or c.handled.containsOrIncl(name.sym.id)):
# forward declaration, skip the body:
return
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
toNifDecl(name, n, c)
if visibility != nil:
c.b.addRaw " x"
else:
c.b.addEmpty
for i in 1..min(bodyPos, n.len-1):
if i == pragmasPos:
toNifPragmas(n[i], n, c, name)
elif i == miscPos:
c.b.addEmpty
elif i == bodyPos:
if name.kind == nkSym and name.sym.ast != nil:
# use the semchecked body:
toNifProcBody(c.graph.getBody(name.sym), n, c, name)
else:
toNifProcBody(n[i], n, c, name)
else:
toNif(n[i], n, c)
c.b.endTree()
of nkVarTuple:
relLineInfo(n, parent, c)
assert n[n.len-2].kind == nkEmpty
c.b.addTree("unpackdecl")
toNif(n[n.len-1], n, c, allowEmpty = true)
c.b.addTree("unpacktup")
for i in 0..<n.len-2:
if n[i].kind == nkVarTuple:
toNif(n[i], n, c)
else:
c.b.addTree($c.section)
let split = splitIdentDefName(n[i])
toNifDecl(split.name, n, c) # name
if split.visibility != nil:
c.b.addRaw " x"
else:
c.b.addEmpty
if split.pragma != nil:
toNif(split.pragma, n, c)
else:
c.b.addEmpty
c.b.addEmpty 2 # type, value
c.b.endTree()
c.b.endTree()
c.b.endTree()
of nkForStmt:
relLineInfo(n, parent, c)
c.b.addTree("for")
toNif(n[n.len-2], n, c) # iterator
if n.len == 3 and n[0].kind == nkVarTuple:
toVarTuple(n[0], n, c)
else:
c.b.addTree("unpackflat")
for i in 0..<n.len-2:
if n[i].kind == nkVarTuple:
toVarTuple(n[i], n, c)
else:
c.b.addTree("let")
toNifDecl(n[i], n, c) # name
c.b.addEmpty 4 # export marker, pragmas, type, value
c.b.endTree() # LetDecl
c.b.endTree() # UnpackIntoFlat
# for-loop-body:
toNif(n[n.len-1], n, c)
c.b.endTree()
of nkRefTy, nkPtrTy:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkObjectTy:
let kind = nodeKindTranslation(n.kind)
c.section = FldL
relLineInfo(n, parent, c)
c.b.addTree(kind)
for i in 0..<n.len-3:
toNif(n[i], n, c, allowEmpty = true)
# n.len-3: pragmas: must be empty (it is deprecated anyway)
if n.len == 0:
# object typeclass, has no children
discard
else:
if n[n.len-3].kind != nkEmpty:
c.b.addTree "err"
c.b.endTree()
toNif(n[n.len-2], n, c, allowEmpty = true)
let last {.cursor.} = n[n.len-1]
if last.kind == nkRecList:
for child in last:
toNif(child, n, c)
elif last.kind != nkEmpty:
toNif(last, n, c)
c.b.endTree()
of nkTupleTy, nkTupleClassTy:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
assert n[i].kind == nkIdentDefs
let def = n[i]
let last = def.len - 1
for j in 0..last - 2:
relLineInfo(def[j], parent, c)
c.b.addTree "kv"
let split = splitIdentDefName(def[j])
toNifDecl(split.name, def[j], c) # name
toNif(def[last-1], def[j], c, allowEmpty = true) # type
c.b.endTree()
c.b.endTree()
of nkImportStmt, nkFromStmt, nkExportStmt, nkExportExceptStmt, nkImportAs, nkImportExceptStmt, nkIncludeStmt:
# the usual recursion:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
if c.depsEnabled:
let oldLineInfoEnabled = c.lineInfoEnabled
c.lineInfoEnabled = false
let oldDepsEnabled = c.depsEnabled
swap c.b, c.deps
c.depsEnabled = false
toNif(n, nil, c)
c.depsEnabled = oldDepsEnabled
swap c.b, c.deps
c.lineInfoEnabled = oldLineInfoEnabled
of nkCallKinds:
let oldDepsEnabled = c.depsEnabled
if n.len > 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..<n.len:
toNif(n[i], n, c)
c.b.endTree()
c.depsEnabled = oldDepsEnabled
of nkReturnStmt:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
if n.len > 0 and n[0].kind in {nkAsgn, nkFastAsgn}:
toNif(n[0][1], n, c)
else:
for i in 0..<n.len:
toNif(n[i], n, c, allowEmpty = true)
c.b.endTree()
of nkDiscardStmt, nkBreakStmt, nkContinueStmt, nkRaiseStmt,
nkBlockStmt, nkBlockExpr, nkBlockType, nkTypeClassTy, nkAsmStmt:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
toNif(n[i], n, c, allowEmpty = true)
c.b.endTree()
of nkExceptBranch:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
if n.len == 1:
c.b.addEmpty 1
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkCurly:
relLineInfo(n, parent, c)
c.b.addTree("setconstr")
toNifType(n.typ, n, c)
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkBracket:
relLineInfo(n, parent, c)
c.b.addTree("aconstr")
toNifType(n.typ, n, c)
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkTupleConstr:
relLineInfo(n, parent, c)
c.b.addTree("tupconstr")
toNifType(n.typ, n, c)
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkCast:
relLineInfo(n, parent, c)
c.b.addTree("cast")
toNifType(n.typ, n, c)
toNif(n[1], n, c)
c.b.endTree()
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
# XXX Special case conversions to and from OpenArray which are not builtin for Nimony
relLineInfo(n, parent, c)
c.b.addTree("conv")
toNifType(n.typ, n, c)
toNif(n[1], n, c)
c.b.endTree()
of nkCheckedFieldExpr:
toNif(n[0], n, c)
of nkObjUpConv, nkObjDownConv:
let diff = inheritanceDiff(n.typ, n[0].typ)
relLineInfo(n, parent, c)
c.b.addTree("baseobj")
toNifType(n.typ, n, c)
c.b.addIntLit diff
toNif(n[0], n, c)
c.b.endTree()
of nkObjConstr:
relLineInfo(n, parent, c)
c.b.addTree("oconstr")
# starts with the type as we need it. But maybe it got inferred:
var start = 0
if n.len > 0 and n[0].kind == nkEmpty:
toNifType(n.typ, n, c)
start = 1
for i in start..<n.len:
toNif(n[i], n, c)
c.b.endTree()
of nkStringToCString:
relLineInfo(n, parent, c)
c.b.addTree("call")
c.b.addSymbol("toCString.0." & SystemModuleSuffix)
c.b.withTree "haddr":
toNif(n[0], n, c)
c.b.endTree()
of nkCStringToString:
relLineInfo(n, parent, c)
c.b.addTree("call")
c.b.addSymbol("fromCString.0." & SystemModuleSuffix)
toNif(n[0], n, c)
c.b.endTree()
else:
relLineInfo(n, parent, c)
c.b.addTree(nodeKindTranslation(n.kind))
for i in 0..<n.len:
toNif(n[i], n, c)
c.b.endTree()
proc close*(c: var TranslationContext) =
c.b.endTree()
c.b.close()
if c.depsEnabled:
c.deps.endTree()
c.deps.close()
proc toNifStmts(n: PNode, c: var TranslationContext) =
if n.kind == nkStmtList:
for i in 0..<n.len:
toNif(n[i], nil, c)
else:
toNif(n, nil, c)
proc closeNif*(graph: ModuleGraph; bModule: PPassContext; finalNode: PNode) =
let m = NifModule(bModule)
if finalNode != nil and finalNode.kind != nkEmpty:
toNifStmts(finalNode, m.tc)
m.tc.close()
# Rename the file to `.nim2.nif` as file renames are atomic on the OSes we care about.
moveFile(m.outfile, m.outfile.changeFileExt(".nim2.nif"))
proc setupNifgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
let conf = graph.config
let nimcacheDir = getNimcacheDir(conf).string
# Ensure nimcache directory exists
if not dirExists(nimcacheDir):
createDir(nimcacheDir)
var c = TranslationContext(conf: conf,
portablePaths: true, depsEnabled: false, lineInfoEnabled: true, graph: graph)
# `nim nif` can run in parallel writing to the same nimcache/. So we produce
# a unique name here and then rename the file in `closeNif` to `.nim2.nif` as
# file renames are atomic on the OSes we care about:
let outfile = nimcacheDir / modname(c, FileIndex module.position) & "." & c.projectHash & ".nif"
c.b = nifbuilder.open(outfile)
if c.depsEnabled:
c.deps = nifbuilder.open(outfile.changeFileExt(".nim2.deps.nif"))
c.b.addHeader "nim2", "nim-parsed"
c.b.addRaw "(.original "
c.b.addStrLit module.name.s
c.b.addRaw ")\n"
c.b.addTree "stmts"
if c.depsEnabled:
c.deps.addHeader "nim2", "nim-deps"
c.deps.addTree "stmts"
var m = NifModule(graph: graph, module: module, idgen: idgen, tc: c, outfile: outfile)
result = m
proc genTopLevelNif*(bModule: PPassContext; n: PNode) =
let m = NifModule(bModule)
toNifStmts(n, m.tc)