From 6da44d833fced53ebbe9a0c4c6967a67e1735c22 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Thu, 2 Oct 2025 18:12:17 +0900 Subject: [PATCH 01/21] adds Nim's AST to/from NIF --- compiler/icnif/enum2nif.nim | 1829 +++++++++++++++++++++++++++++++++ compiler/icnif/nifdecoder.nim | 105 ++ compiler/icnif/nifencoder.nim | 56 + compiler/pipelines.nim | 8 + tests/icnif/tencode.nim | 20 + 5 files changed, 2018 insertions(+) create mode 100644 compiler/icnif/enum2nif.nim create mode 100644 compiler/icnif/nifdecoder.nim create mode 100644 compiler/icnif/nifencoder.nim create mode 100644 tests/icnif/tencode.nim diff --git a/compiler/icnif/enum2nif.nim b/compiler/icnif/enum2nif.nim new file mode 100644 index 0000000000000..a4bbbf6e902d1 --- /dev/null +++ b/compiler/icnif/enum2nif.nim @@ -0,0 +1,1829 @@ +# Generated by enumgen.nim. DO NOT EDIT! + +import ".." / [ast, options] + +proc toNifTag*(s: TNodeKind): string = + case s + of nkNone: "none" + of nkEmpty: "empty" + of nkIdent: "ident" + of nkSym: "sym" + of nkType: "onlytype" + of nkCharLit: "charlit" + of nkIntLit: "intlit" + of nkInt8Lit: "int8lit" + of nkInt16Lit: "int16lit" + of nkInt32Lit: "int32lit" + of nkInt64Lit: "int64lit" + of nkUIntLit: "uintlit" + of nkUInt8Lit: "uint8lit" + of nkUInt16Lit: "uint16lit" + of nkUInt32Lit: "uint32lit" + of nkUInt64Lit: "uint64lit" + of nkFloatLit: "floatlit" + of nkFloat32Lit: "float32lit" + of nkFloat64Lit: "float64lit" + of nkFloat128Lit: "float128lit" + of nkStrLit: "strlit" + of nkRStrLit: "rstrlit" + of nkTripleStrLit: "triplestrlit" + of nkNilLit: "nillit" + of nkComesFrom: "comesfrom" + of nkDotCall: "dotcall" + of nkCommand: "cmd" + of nkCall: "call" + of nkCallStrLit: "callstrlit" + of nkInfix: "infix" + of nkPrefix: "prefix" + of nkPostfix: "postfix" + of nkHiddenCallConv: "hcallconv" + of nkExprEqExpr: "vv" + of nkExprColonExpr: "kv" + of nkIdentDefs: "identdefs" + of nkVarTuple: "vartuple" + of nkPar: "par" + of nkObjConstr: "objconstr" + of nkCurly: "curly" + of nkCurlyExpr: "curlyx" + of nkBracket: "bracket" + of nkBracketExpr: "at" + of nkPragmaExpr: "pragmax" + of nkRange: "range" + of nkDotExpr: "dot" + of nkCheckedFieldExpr: "checkedfieldx" + of nkDerefExpr: "deref" + of nkIfExpr: "ifx" + of nkElifExpr: "elifx" + of nkElseExpr: "elsex" + of nkLambda: "lambda" + of nkDo: "do" + of nkAccQuoted: "accquoted" + of nkTableConstr: "tableconstr" + of nkBind: "bind" + of nkClosedSymChoice: "closedsymchoice" + of nkOpenSymChoice: "opensymchoice" + of nkHiddenStdConv: "hstdconv" + of nkHiddenSubConv: "hsubconv" + of nkConv: "conv" + of nkCast: "cast" + of nkStaticExpr: "staticx" + of nkAddr: "addr" + of nkHiddenAddr: "haddr" + of nkHiddenDeref: "hderef" + of nkObjDownConv: "objdownconv" + of nkObjUpConv: "objupconv" + of nkChckRangeF: "chckrangef" + of nkChckRange64: "chckrange64" + of nkChckRange: "chckrange" + of nkStringToCString: "stringtocstring" + of nkCStringToString: "cstringtostring" + of nkAsgn: "asgn" + of nkFastAsgn: "fastasgn" + of nkGenericParams: "genericparams" + of nkFormalParams: "formalparams" + of nkOfInherit: "ofinherit" + of nkImportAs: "importas" + of nkProcDef: "proc" + of nkMethodDef: "method" + of nkConverterDef: "converter" + of nkMacroDef: "macro" + of nkTemplateDef: "template" + of nkIteratorDef: "iterator" + of nkOfBranch: "of" + of nkElifBranch: "elif" + of nkExceptBranch: "except" + of nkElse: "else" + of nkAsmStmt: "asm" + of nkPragma: "pragma" + of nkPragmaBlock: "pragmablock" + of nkIfStmt: "if" + of nkWhenStmt: "when" + of nkForStmt: "for" + of nkParForStmt: "parfor" + of nkWhileStmt: "while" + of nkCaseStmt: "case" + of nkTypeSection: "type" + of nkVarSection: "var" + of nkLetSection: "let" + of nkConstSection: "const" + of nkConstDef: "const0" + of nkTypeDef: "type0" + of nkYieldStmt: "yield" + of nkDefer: "defer" + of nkTryStmt: "try" + of nkFinally: "finally" + of nkRaiseStmt: "raise" + of nkReturnStmt: "ret" + of nkBreakStmt: "brk" + of nkContinueStmt: "continue" + of nkBlockStmt: "block" + of nkStaticStmt: "static" + of nkDiscardStmt: "discard" + of nkStmtList: "stmts" + of nkImportStmt: "import" + of nkImportExceptStmt: "importexcept" + of nkExportStmt: "export" + of nkExportExceptStmt: "exportexcept" + of nkFromStmt: "from" + of nkIncludeStmt: "include" + of nkBindStmt: "bind0" + of nkMixinStmt: "mixin" + of nkUsingStmt: "using" + of nkCommentStmt: "comment" + of nkStmtListExpr: "expr" + of nkBlockExpr: "blockx" + of nkStmtListType: "stmtlisttype" + of nkBlockType: "blocktype" + of nkWith: "with" + of nkWithout: "without" + of nkTypeOfExpr: "typeofx" + of nkObjectTy: "objectty" + of nkTupleTy: "tuplety" + of nkTupleClassTy: "tupleclassty" + of nkTypeClassTy: "typeclassty" + of nkStaticTy: "staticty" + of nkRecList: "reclist" + of nkRecCase: "reccase" + of nkRecWhen: "recwhen" + of nkRefTy: "refty" + of nkPtrTy: "ptrty" + of nkVarTy: "varty" + of nkConstTy: "constty" + of nkOutTy: "outty" + of nkDistinctTy: "distinctty" + of nkProcTy: "procty" + of nkIteratorTy: "iteratorty" + of nkSinkAsgn: "sinkasgn" + of nkEnumTy: "enumty" + of nkEnumFieldDef: "efld" + of nkArgList: "arglist" + of nkPattern: "pattern" + of nkHiddenTryStmt: "htrystmt" + of nkClosure: "closure" + of nkGotoState: "gotostate" + of nkState: "state" + of nkBreakState: "breakstate" + of nkFuncDef: "func" + of nkTupleConstr: "tupleconstr" + of nkError: "err" + of nkModuleRef: "moduleref" + of nkReplayAction: "replayaction" + of nkNilRodNode: "nilrodnode" + of nkOpenSym: "opensym" + + +proc parseNodeKind*(s: string): TNodeKind = + case s + of "none": nkNone + of "empty": nkEmpty + of "ident": nkIdent + of "sym": nkSym + of "onlytype": nkType + of "charlit": nkCharLit + of "intlit": nkIntLit + of "int8lit": nkInt8Lit + of "int16lit": nkInt16Lit + of "int32lit": nkInt32Lit + of "int64lit": nkInt64Lit + of "uintlit": nkUIntLit + of "uint8lit": nkUInt8Lit + of "uint16lit": nkUInt16Lit + of "uint32lit": nkUInt32Lit + of "uint64lit": nkUInt64Lit + of "floatlit": nkFloatLit + of "float32lit": nkFloat32Lit + of "float64lit": nkFloat64Lit + of "float128lit": nkFloat128Lit + of "strlit": nkStrLit + of "rstrlit": nkRStrLit + of "triplestrlit": nkTripleStrLit + of "nillit": nkNilLit + of "comesfrom": nkComesFrom + of "dotcall": nkDotCall + of "cmd": nkCommand + of "call": nkCall + of "callstrlit": nkCallStrLit + of "infix": nkInfix + of "prefix": nkPrefix + of "postfix": nkPostfix + of "hcallconv": nkHiddenCallConv + of "vv": nkExprEqExpr + of "kv": nkExprColonExpr + of "identdefs": nkIdentDefs + of "vartuple": nkVarTuple + of "par": nkPar + of "objconstr": nkObjConstr + of "curly": nkCurly + of "curlyx": nkCurlyExpr + of "bracket": nkBracket + of "at": nkBracketExpr + of "pragmax": nkPragmaExpr + of "range": nkRange + of "dot": nkDotExpr + of "checkedfieldx": nkCheckedFieldExpr + of "deref": nkDerefExpr + of "ifx": nkIfExpr + of "elifx": nkElifExpr + of "elsex": nkElseExpr + of "lambda": nkLambda + of "do": nkDo + of "accquoted": nkAccQuoted + of "tableconstr": nkTableConstr + of "bind": nkBind + of "closedsymchoice": nkClosedSymChoice + of "opensymchoice": nkOpenSymChoice + of "hstdconv": nkHiddenStdConv + of "hsubconv": nkHiddenSubConv + of "conv": nkConv + of "cast": nkCast + of "staticx": nkStaticExpr + of "addr": nkAddr + of "haddr": nkHiddenAddr + of "hderef": nkHiddenDeref + of "objdownconv": nkObjDownConv + of "objupconv": nkObjUpConv + of "chckrangef": nkChckRangeF + of "chckrange64": nkChckRange64 + of "chckrange": nkChckRange + of "stringtocstring": nkStringToCString + of "cstringtostring": nkCStringToString + of "asgn": nkAsgn + of "fastasgn": nkFastAsgn + of "genericparams": nkGenericParams + of "formalparams": nkFormalParams + of "ofinherit": nkOfInherit + of "importas": nkImportAs + of "proc": nkProcDef + of "method": nkMethodDef + of "converter": nkConverterDef + of "macro": nkMacroDef + of "template": nkTemplateDef + of "iterator": nkIteratorDef + of "of": nkOfBranch + of "elif": nkElifBranch + of "except": nkExceptBranch + of "else": nkElse + of "asm": nkAsmStmt + of "pragma": nkPragma + of "pragmablock": nkPragmaBlock + of "if": nkIfStmt + of "when": nkWhenStmt + of "for": nkForStmt + of "parfor": nkParForStmt + of "while": nkWhileStmt + of "case": nkCaseStmt + of "type": nkTypeSection + of "var": nkVarSection + of "let": nkLetSection + of "const": nkConstSection + of "const0": nkConstDef + of "type0": nkTypeDef + of "yield": nkYieldStmt + of "defer": nkDefer + of "try": nkTryStmt + of "finally": nkFinally + of "raise": nkRaiseStmt + of "ret": nkReturnStmt + of "brk": nkBreakStmt + of "continue": nkContinueStmt + of "block": nkBlockStmt + of "static": nkStaticStmt + of "discard": nkDiscardStmt + of "stmts": nkStmtList + of "import": nkImportStmt + of "importexcept": nkImportExceptStmt + of "export": nkExportStmt + of "exportexcept": nkExportExceptStmt + of "from": nkFromStmt + of "include": nkIncludeStmt + of "bind0": nkBindStmt + of "mixin": nkMixinStmt + of "using": nkUsingStmt + of "comment": nkCommentStmt + of "expr": nkStmtListExpr + of "blockx": nkBlockExpr + of "stmtlisttype": nkStmtListType + of "blocktype": nkBlockType + of "with": nkWith + of "without": nkWithout + of "typeofx": nkTypeOfExpr + of "objectty": nkObjectTy + of "tuplety": nkTupleTy + of "tupleclassty": nkTupleClassTy + of "typeclassty": nkTypeClassTy + of "staticty": nkStaticTy + of "reclist": nkRecList + of "reccase": nkRecCase + of "recwhen": nkRecWhen + of "refty": nkRefTy + of "ptrty": nkPtrTy + of "varty": nkVarTy + of "constty": nkConstTy + of "outty": nkOutTy + of "distinctty": nkDistinctTy + of "procty": nkProcTy + of "iteratorty": nkIteratorTy + of "sinkasgn": nkSinkAsgn + of "enumty": nkEnumTy + of "efld": nkEnumFieldDef + of "arglist": nkArgList + of "pattern": nkPattern + of "htrystmt": nkHiddenTryStmt + of "closure": nkClosure + of "gotostate": nkGotoState + of "state": nkState + of "breakstate": nkBreakState + of "func": nkFuncDef + of "tupleconstr": nkTupleConstr + of "err": nkError + of "moduleref": nkModuleRef + of "replayaction": nkReplayAction + of "nilrodnode": nkNilRodNode + of "opensym": nkOpenSym + else: nkNone + + +proc toNifTag*(s: TSymKind): string = + case s + of skUnknown: "unknown" + of skConditional: "conditional" + of skDynLib: "dynlib" + of skParam: "param" + of skGenericParam: "genericparam" + of skTemp: "temp" + of skModule: "module" + of skType: "type" + of skVar: "var" + of skLet: "let" + of skConst: "const" + of skResult: "result" + of skProc: "proc" + of skFunc: "func" + of skMethod: "method" + of skIterator: "iterator" + of skConverter: "converter" + of skMacro: "macro" + of skTemplate: "template" + of skField: "field" + of skEnumField: "enumfield" + of skForVar: "forvar" + of skLabel: "label" + of skStub: "stub" + of skPackage: "package" + + +proc parseSymKind*(s: string): TSymKind = + case s + of "unknown": skUnknown + of "conditional": skConditional + of "dynlib": skDynLib + of "param": skParam + of "genericparam": skGenericParam + of "temp": skTemp + of "module": skModule + of "type": skType + of "var": skVar + of "let": skLet + of "const": skConst + of "result": skResult + of "proc": skProc + of "func": skFunc + of "method": skMethod + of "iterator": skIterator + of "converter": skConverter + of "macro": skMacro + of "template": skTemplate + of "field": skField + of "enumfield": skEnumField + of "forvar": skForVar + of "label": skLabel + of "stub": skStub + of "package": skPackage + else: skUnknown + + +proc toNifTag*(s: TTypeKind): string = + case s + of tyNone: "none" + of tyBool: "bool" + of tyChar: "char" + of tyEmpty: "empty" + of tyAlias: "alias" + of tyNil: "nil" + of tyUntyped: "untyped" + of tyTyped: "typed" + of tyTypeDesc: "typedesc" + of tyGenericInvocation: "ginvoke" + of tyGenericBody: "gbody" + of tyGenericInst: "ginst" + 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: "fromx" + of tyConcept: "concept" + of tyVoid: "void" + of tyIterable: "iterable" + + +proc parseTypeKind*(s: string): TTypeKind = + case s + of "none": tyNone + of "bool": tyBool + of "char": tyChar + of "empty": tyEmpty + of "alias": tyAlias + of "nil": tyNil + of "untyped": tyUntyped + of "typed": tyTyped + of "typedesc": tyTypeDesc + of "ginvoke": tyGenericInvocation + of "gbody": tyGenericBody + of "ginst": tyGenericInst + of "gparam": tyGenericParam + of "distinct": tyDistinct + of "enum": tyEnum + of "ordinal": tyOrdinal + of "array": tyArray + of "object": tyObject + of "tuple": tyTuple + of "set": tySet + of "range": tyRange + of "ptr": tyPtr + of "ref": tyRef + of "mut": tyVar + of "seq": tySequence + of "proctype": tyProc + of "pointer": tyPointer + of "openarray": tyOpenArray + of "string": tyString + of "cstring": tyCstring + of "forward": tyForward + of "int": tyInt + of "int8": tyInt8 + of "int16": tyInt16 + of "int32": tyInt32 + of "int64": tyInt64 + of "float": tyFloat + of "float32": tyFloat32 + of "float64": tyFloat64 + of "float128": tyFloat128 + of "uint": tyUInt + of "uint8": tyUInt8 + of "uint16": tyUInt16 + of "uint32": tyUInt32 + of "uint64": tyUInt64 + of "owned": tyOwned + of "sink": tySink + of "lent": tyLent + of "varargs": tyVarargs + of "uarray": tyUncheckedArray + of "error": tyError + of "bconcept": tyBuiltInTypeClass + of "uconcept": tyUserTypeClass + of "uconceptinst": tyUserTypeClassInst + of "cconcept": tyCompositeTypeClass + of "inferred": tyInferred + of "and": tyAnd + of "or": tyOr + of "not": tyNot + of "anything": tyAnything + of "static": tyStatic + of "fromx": tyFromExpr + of "concept": tyConcept + of "void": tyVoid + of "iterable": tyIterable + else: tyNone + + +proc toNifTag*(s: TLocKind): string = + case s + of locNone: "none" + of locTemp: "temp" + of locLocalVar: "localvar" + of locGlobalVar: "globalvar" + of locParam: "param" + of locField: "field" + of locExpr: "expr" + of locProc: "proc" + of locData: "data" + of locCall: "call" + of locOther: "other" + + +proc parseLocKind*(s: string): TLocKind = + case s + of "none": locNone + of "temp": locTemp + of "localvar": locLocalVar + of "globalvar": locGlobalVar + of "param": locParam + of "field": locField + of "expr": locExpr + of "proc": locProc + of "data": locData + of "call": locCall + of "other": locOther + else: locNone + + +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 parseCallingConvention*(s: string): TCallingConvention = + case s + of "nimcall": ccNimCall + of "stdcall": ccStdCall + of "cdecl": ccCDecl + of "safecall": ccSafeCall + of "syscall": ccSysCall + of "inline": ccInline + of "noinline": ccNoInline + of "fastcall": ccFastCall + of "thiscall": ccThisCall + of "closure": ccClosure + of "noconv": ccNoConvention + of "member": ccMember + else: ccNimCall + + +proc toNifTag*(s: TMagic): string = + case s + of mNone: "nonem" + of mDefined: "defined" + of mDeclared: "declared" + of mDeclaredInScope: "declaredinscope" + of mCompiles: "compiles" + of mArrGet: "arrget" + of mArrPut: "arrput" + of mAsgn: "asgnm" + of mLow: "low" + of mHigh: "high" + of mSizeOf: "sizeof" + of mAlignOf: "alignof" + of mOffsetOf: "offsetof" + of mTypeTrait: "typetrait" + of mIs: "is" + of mOf: "ofm" + of mAddr: "addrm" + of mType: "typem" + of mTypeOf: "typeof" + of mPlugin: "plugin" + of mEcho: "echo" + of mShallowCopy: "shallowcopy" + of mSlurp: "slurp" + of mStaticExec: "staticexec" + of mStatic: "staticm" + of mParseExprToAst: "parseexprtoast" + of mParseStmtToAst: "parsestmttoast" + of mExpandToAst: "expandtoast" + of mQuoteAst: "quoteast" + of mInc: "inc" + of mDec: "dec" + of mOrd: "ord" + of mNew: "new" + of mNewFinalize: "newfinalize" + of mNewSeq: "newseq" + of mNewSeqOfCap: "newseqofcap" + of mLengthOpenArray: "lenopenarray" + of mLengthStr: "lenstr" + of mLengthArray: "lenarray" + of mLengthSeq: "lenseq" + of mIncl: "incl" + of mExcl: "excl" + of mCard: "card" + of mChr: "chr" + of mGCref: "gcref" + of mGCunref: "gcunref" + of mAddI: "add" + of mSubI: "sub" + of mMulI: "mul" + of mDivI: "div" + of mModI: "mod" + of mSucc: "succ" + of mPred: "pred" + of mAddF64: "addf64" + of mSubF64: "subf64" + of mMulF64: "mulf64" + of mDivF64: "divf64" + of mShrI: "shr" + of mShlI: "shl" + of mAshrI: "ashr" + of mBitandI: "bitand" + of mBitorI: "bitor" + of mBitxorI: "bitxor" + of mMinI: "min" + of mMaxI: "max" + of mAddU: "addu" + of mSubU: "subu" + of mMulU: "mulu" + of mDivU: "divu" + of mModU: "modu" + of mEqI: "eq" + of mLeI: "le" + of mLtI: "lt" + of mEqF64: "eqf64" + of mLeF64: "lef64" + of mLtF64: "ltf64" + of mLeU: "leu" + of mLtU: "ltu" + of mEqEnum: "eqenum" + of mLeEnum: "leenum" + of mLtEnum: "ltenum" + of mEqCh: "eqch" + of mLeCh: "lech" + of mLtCh: "ltch" + of mEqB: "eqb" + of mLeB: "leb" + of mLtB: "ltb" + of mEqRef: "eqref" + of mLePtr: "leptr" + of mLtPtr: "ltptr" + of mXor: "xor" + of mEqCString: "eqcstring" + of mEqProc: "eqproc" + of mUnaryMinusI: "unaryminus" + of mUnaryMinusI64: "unaryminusi64" + of mAbsI: "abs" + of mNot: "not" + of mUnaryPlusI: "unaryplus" + of mBitnotI: "bitnot" + of mUnaryPlusF64: "unaryplusf64" + of mUnaryMinusF64: "unaryminusf64" + of mCharToStr: "chartostr" + of mBoolToStr: "booltostr" + of mCStrToStr: "cstrtostr" + of mStrToStr: "strtostr" + of mEnumToStr: "enumtostr" + of mAnd: "and" + of mOr: "or" + of mImplies: "implies" + of mIff: "iff" + of mExists: "exists" + of mForall: "forall" + of mOld: "old" + of mEqStr: "eqstr" + of mLeStr: "lestr" + of mLtStr: "ltstr" + of mEqSet: "eqset" + of mLeSet: "leset" + of mLtSet: "ltset" + of mMulSet: "mulset" + of mPlusSet: "plusset" + of mMinusSet: "minusset" + of mXorSet: "xorset" + of mConStrStr: "constrstr" + of mSlice: "slice" + of mDotDot: "dotdot" + of mFields: "fields" + of mFieldPairs: "fieldpairs" + of mOmpParFor: "ompparfor" + of mAppendStrCh: "addstrch" + of mAppendStrStr: "addstrstr" + of mAppendSeqElem: "addseqelem" + of mInSet: "contains" + of mRepr: "repr" + of mExit: "exit" + of mSetLengthStr: "setlenstr" + of mSetLengthSeq: "setlenseq" + of mSetLengthSeqUninit: "setlensequninit" + of mIsPartOf: "ispartof" + of mAstToStr: "asttostr" + of mParallel: "parallel" + of mSwap: "swap" + of mIsNil: "isnil" + of mArrToSeq: "arrtoseq" + of mOpenArrayToSeq: "openarraytoseq" + of mNewString: "newstring" + of mNewStringOfCap: "newstringofcap" + of mParseBiggestFloat: "parsebiggestfloat" + of mMove: "move" + of mEnsureMove: "ensuremove" + of mWasMoved: "wasmoved" + of mDup: "dup" + of mDestroy: "destroy" + of mTrace: "trace" + of mDefault: "default" + of mUnown: "unown" + of mFinished: "finished" + of mIsolate: "isolate" + of mAccessEnv: "accessenv" + of mAccessTypeField: "accesstypefield" + of mArray: "array" + of mOpenArray: "openarray" + of mRange: "rangem" + of mSet: "set" + of mSeq: "seq" + of mVarargs: "varargs" + of mRef: "ref" + of mPtr: "ptr" + of mVar: "varm" + of mDistinct: "distinct" + of mVoid: "void" + of mTuple: "tuple" + of mOrdinal: "ordinal" + of mIterableType: "iterabletype" + of mInt: "int" + of mInt8: "int8" + of mInt16: "int16" + of mInt32: "int32" + of mInt64: "int64" + of mUInt: "uint" + of mUInt8: "uint8" + of mUInt16: "uint16" + of mUInt32: "uint32" + of mUInt64: "uint64" + of mFloat: "float" + of mFloat32: "float32" + of mFloat64: "float64" + of mFloat128: "float128" + of mBool: "bool" + of mChar: "char" + of mString: "string" + of mCstring: "cstring" + of mPointer: "pointer" + of mNil: "nil" + of mExpr: "exprm" + of mStmt: "stmtm" + of mTypeDesc: "typedesc" + of mVoidType: "voidtype" + of mPNimrodNode: "nimnode" + of mSpawn: "spawn" + of mDeepCopy: "deepcopy" + of mIsMainModule: "ismainmodule" + of mCompileDate: "compiledate" + of mCompileTime: "compiletime" + of mProcCall: "proccall" + of mCpuEndian: "cpuendian" + of mHostOS: "hostos" + of mHostCPU: "hostcpu" + of mBuildOS: "buildos" + of mBuildCPU: "buildcpu" + of mAppType: "apptype" + of mCompileOption: "compileoption" + of mCompileOptionArg: "compileoptionarg" + of mNLen: "nlen" + of mNChild: "nchild" + of mNSetChild: "nsetchild" + of mNAdd: "nadd" + of mNAddMultiple: "naddmultiple" + of mNDel: "ndel" + of mNKind: "nkind" + of mNSymKind: "nsymkind" + of mNccValue: "nccvalue" + of mNccInc: "nccinc" + of mNcsAdd: "ncsadd" + of mNcsIncl: "ncsincl" + of mNcsLen: "ncslen" + of mNcsAt: "ncsat" + of mNctPut: "nctput" + of mNctLen: "nctlen" + of mNctGet: "nctget" + of mNctHasNext: "ncthasnext" + of mNctNext: "nctnext" + of mNIntVal: "nintval" + of mNFloatVal: "nfloatval" + of mNSymbol: "nsymbol" + of mNIdent: "nident" + of mNGetType: "ngettype" + of mNStrVal: "nstrval" + of mNSetIntVal: "nsetintval" + of mNSetFloatVal: "nsetfloatval" + of mNSetSymbol: "nsetsymbol" + of mNSetIdent: "nsetident" + of mNSetStrVal: "nsetstrval" + of mNLineInfo: "nlineinfo" + of mNNewNimNode: "nnewnimnode" + of mNCopyNimNode: "ncopynimnode" + of mNCopyNimTree: "ncopynimtree" + of mStrToIdent: "strtoident" + of mNSigHash: "nsighash" + of mNSizeOf: "nsizeof" + of mNBindSym: "nbindsym" + of mNCallSite: "ncallsite" + of mEqIdent: "eqident" + of mEqNimrodNode: "eqnimnode" + of mSameNodeType: "samenodetype" + of mGetImpl: "getimpl" + of mNGenSym: "ngensym" + of mNHint: "nhint" + of mNWarning: "nwarning" + of mNError: "nerror" + of mInstantiationInfo: "instantiationinfo" + of mGetTypeInfo: "gettypeinfo" + of mGetTypeInfoV2: "gettypeinfov2" + of mNimvm: "nimvm" + of mIntDefine: "intdefine" + of mStrDefine: "strdefine" + of mBoolDefine: "booldefine" + of mGenericDefine: "genericdefine" + of mRunnableExamples: "runnableexamples" + of mException: "exception" + of mBuiltinType: "builtintype" + of mSymOwner: "symowner" + of mUncheckedArray: "uncheckedarray" + of mGetImplTransf: "getimpltransf" + of mSymIsInstantiationOf: "symisinstantiationof" + of mNodeId: "nodeid" + of mPrivateAccess: "privateaccess" + of mZeroDefault: "zerodefault" + + +proc parseMagic*(s: string): TMagic = + case s + of "nonem": mNone + of "defined": mDefined + of "declared": mDeclared + of "declaredinscope": mDeclaredInScope + of "compiles": mCompiles + of "arrget": mArrGet + of "arrput": mArrPut + of "asgnm": mAsgn + of "low": mLow + of "high": mHigh + of "sizeof": mSizeOf + of "alignof": mAlignOf + of "offsetof": mOffsetOf + of "typetrait": mTypeTrait + of "is": mIs + of "ofm": mOf + of "addrm": mAddr + of "typem": mType + of "typeof": mTypeOf + of "plugin": mPlugin + of "echo": mEcho + of "shallowcopy": mShallowCopy + of "slurp": mSlurp + of "staticexec": mStaticExec + of "staticm": mStatic + of "parseexprtoast": mParseExprToAst + of "parsestmttoast": mParseStmtToAst + of "expandtoast": mExpandToAst + of "quoteast": mQuoteAst + of "inc": mInc + of "dec": mDec + of "ord": mOrd + of "new": mNew + of "newfinalize": mNewFinalize + of "newseq": mNewSeq + of "newseqofcap": mNewSeqOfCap + of "lenopenarray": mLengthOpenArray + of "lenstr": mLengthStr + of "lenarray": mLengthArray + of "lenseq": mLengthSeq + of "incl": mIncl + of "excl": mExcl + of "card": mCard + of "chr": mChr + of "gcref": mGCref + of "gcunref": mGCunref + of "add": mAddI + of "sub": mSubI + of "mul": mMulI + of "div": mDivI + of "mod": mModI + of "succ": mSucc + of "pred": mPred + of "addf64": mAddF64 + of "subf64": mSubF64 + of "mulf64": mMulF64 + of "divf64": mDivF64 + of "shr": mShrI + of "shl": mShlI + of "ashr": mAshrI + of "bitand": mBitandI + of "bitor": mBitorI + of "bitxor": mBitxorI + of "min": mMinI + of "max": mMaxI + of "addu": mAddU + of "subu": mSubU + of "mulu": mMulU + of "divu": mDivU + of "modu": mModU + of "eq": mEqI + of "le": mLeI + of "lt": mLtI + of "eqf64": mEqF64 + of "lef64": mLeF64 + of "ltf64": mLtF64 + of "leu": mLeU + of "ltu": mLtU + of "eqenum": mEqEnum + of "leenum": mLeEnum + of "ltenum": mLtEnum + of "eqch": mEqCh + of "lech": mLeCh + of "ltch": mLtCh + of "eqb": mEqB + of "leb": mLeB + of "ltb": mLtB + of "eqref": mEqRef + of "leptr": mLePtr + of "ltptr": mLtPtr + of "xor": mXor + of "eqcstring": mEqCString + of "eqproc": mEqProc + of "unaryminus": mUnaryMinusI + of "unaryminusi64": mUnaryMinusI64 + of "abs": mAbsI + of "not": mNot + of "unaryplus": mUnaryPlusI + of "bitnot": mBitnotI + of "unaryplusf64": mUnaryPlusF64 + of "unaryminusf64": mUnaryMinusF64 + of "chartostr": mCharToStr + of "booltostr": mBoolToStr + of "cstrtostr": mCStrToStr + of "strtostr": mStrToStr + of "enumtostr": mEnumToStr + of "and": mAnd + of "or": mOr + of "implies": mImplies + of "iff": mIff + of "exists": mExists + of "forall": mForall + of "old": mOld + of "eqstr": mEqStr + of "lestr": mLeStr + of "ltstr": mLtStr + of "eqset": mEqSet + of "leset": mLeSet + of "ltset": mLtSet + of "mulset": mMulSet + of "plusset": mPlusSet + of "minusset": mMinusSet + of "xorset": mXorSet + of "constrstr": mConStrStr + of "slice": mSlice + of "dotdot": mDotDot + of "fields": mFields + of "fieldpairs": mFieldPairs + of "ompparfor": mOmpParFor + of "addstrch": mAppendStrCh + of "addstrstr": mAppendStrStr + of "addseqelem": mAppendSeqElem + of "contains": mInSet + of "repr": mRepr + of "exit": mExit + of "setlenstr": mSetLengthStr + of "setlenseq": mSetLengthSeq + of "setlensequninit": mSetLengthSeqUninit + of "ispartof": mIsPartOf + of "asttostr": mAstToStr + of "parallel": mParallel + of "swap": mSwap + of "isnil": mIsNil + of "arrtoseq": mArrToSeq + of "openarraytoseq": mOpenArrayToSeq + of "newstring": mNewString + of "newstringofcap": mNewStringOfCap + of "parsebiggestfloat": mParseBiggestFloat + of "move": mMove + of "ensuremove": mEnsureMove + of "wasmoved": mWasMoved + of "dup": mDup + of "destroy": mDestroy + of "trace": mTrace + of "default": mDefault + of "unown": mUnown + of "finished": mFinished + of "isolate": mIsolate + of "accessenv": mAccessEnv + of "accesstypefield": mAccessTypeField + of "array": mArray + of "openarray": mOpenArray + of "rangem": mRange + of "set": mSet + of "seq": mSeq + of "varargs": mVarargs + of "ref": mRef + of "ptr": mPtr + of "varm": mVar + of "distinct": mDistinct + of "void": mVoid + of "tuple": mTuple + of "ordinal": mOrdinal + of "iterabletype": mIterableType + of "int": mInt + of "int8": mInt8 + of "int16": mInt16 + of "int32": mInt32 + of "int64": mInt64 + of "uint": mUInt + of "uint8": mUInt8 + of "uint16": mUInt16 + of "uint32": mUInt32 + of "uint64": mUInt64 + of "float": mFloat + of "float32": mFloat32 + of "float64": mFloat64 + of "float128": mFloat128 + of "bool": mBool + of "char": mChar + of "string": mString + of "cstring": mCstring + of "pointer": mPointer + of "nil": mNil + of "exprm": mExpr + of "stmtm": mStmt + of "typedesc": mTypeDesc + of "voidtype": mVoidType + of "nimnode": mPNimrodNode + of "spawn": mSpawn + of "deepcopy": mDeepCopy + of "ismainmodule": mIsMainModule + of "compiledate": mCompileDate + of "compiletime": mCompileTime + of "proccall": mProcCall + of "cpuendian": mCpuEndian + of "hostos": mHostOS + of "hostcpu": mHostCPU + of "buildos": mBuildOS + of "buildcpu": mBuildCPU + of "apptype": mAppType + of "compileoption": mCompileOption + of "compileoptionarg": mCompileOptionArg + of "nlen": mNLen + of "nchild": mNChild + of "nsetchild": mNSetChild + of "nadd": mNAdd + of "naddmultiple": mNAddMultiple + of "ndel": mNDel + of "nkind": mNKind + of "nsymkind": mNSymKind + of "nccvalue": mNccValue + of "nccinc": mNccInc + of "ncsadd": mNcsAdd + of "ncsincl": mNcsIncl + of "ncslen": mNcsLen + of "ncsat": mNcsAt + of "nctput": mNctPut + of "nctlen": mNctLen + of "nctget": mNctGet + of "ncthasnext": mNctHasNext + of "nctnext": mNctNext + of "nintval": mNIntVal + of "nfloatval": mNFloatVal + of "nsymbol": mNSymbol + of "nident": mNIdent + of "ngettype": mNGetType + of "nstrval": mNStrVal + of "nsetintval": mNSetIntVal + of "nsetfloatval": mNSetFloatVal + of "nsetsymbol": mNSetSymbol + of "nsetident": mNSetIdent + of "nsetstrval": mNSetStrVal + of "nlineinfo": mNLineInfo + of "nnewnimnode": mNNewNimNode + of "ncopynimnode": mNCopyNimNode + of "ncopynimtree": mNCopyNimTree + of "strtoident": mStrToIdent + of "nsighash": mNSigHash + of "nsizeof": mNSizeOf + of "nbindsym": mNBindSym + of "ncallsite": mNCallSite + of "eqident": mEqIdent + of "eqnimnode": mEqNimrodNode + of "samenodetype": mSameNodeType + of "getimpl": mGetImpl + of "ngensym": mNGenSym + of "nhint": mNHint + of "nwarning": mNWarning + of "nerror": mNError + of "instantiationinfo": mInstantiationInfo + of "gettypeinfo": mGetTypeInfo + of "gettypeinfov2": mGetTypeInfoV2 + of "nimvm": mNimvm + of "intdefine": mIntDefine + of "strdefine": mStrDefine + of "booldefine": mBoolDefine + of "genericdefine": mGenericDefine + of "runnableexamples": mRunnableExamples + of "exception": mException + of "builtintype": mBuiltinType + of "symowner": mSymOwner + of "uncheckedarray": mUncheckedArray + of "getimpltransf": mGetImplTransf + of "symisinstantiationof": mSymIsInstantiationOf + of "nodeid": mNodeId + of "privateaccess": mPrivateAccess + of "zerodefault": mZeroDefault + else: mNone + + +proc genFlags*(s: set[TSymFlag]; dest: var string) = + for e in s: + case e + of sfUsed: dest.add "u" + of sfExported: dest.add "e" + of sfFromGeneric: dest.add "f" + of sfGlobal: dest.add "g" + of sfForward: dest.add "f0" + of sfWasForwarded: dest.add "w" + of sfImportc: dest.add "i" + of sfExportc: dest.add "e0" + of sfMangleCpp: dest.add "m" + of sfVolatile: dest.add "v" + of sfRegister: dest.add "r" + of sfPure: dest.add "p" + of sfNoSideEffect: dest.add "n" + of sfSideEffect: dest.add "s" + of sfMainModule: dest.add "m0" + of sfSystemModule: dest.add "s0" + of sfNoReturn: dest.add "n0" + of sfAddrTaken: dest.add "a" + of sfCompilerProc: dest.add "c" + of sfEscapes: dest.add "e1" + of sfDiscriminant: dest.add "d" + of sfRequiresInit: dest.add "r0" + of sfDeprecated: dest.add "d0" + of sfExplain: dest.add "e2" + of sfError: dest.add "e3" + of sfShadowed: dest.add "s1" + of sfThread: dest.add "t" + of sfCppNonPod: dest.add "c0" + of sfCompileTime: dest.add "c1" + of sfConstructor: dest.add "c2" + of sfDispatcher: dest.add "d1" + of sfBorrow: dest.add "b" + of sfInfixCall: dest.add "i0" + of sfNamedParamCall: dest.add "n1" + of sfDiscardable: dest.add "d2" + of sfOverridden: dest.add "o" + of sfCallsite: dest.add "c3" + of sfGenSym: dest.add "g0" + of sfNonReloadable: dest.add "n2" + of sfGeneratedOp: dest.add "g1" + of sfTemplateParam: dest.add "t0" + of sfCursor: dest.add "c4" + of sfInjectDestructors: dest.add "i1" + of sfNeverRaises: dest.add "n3" + of sfSystemRaisesDefect: dest.add "s2" + of sfUsedInFinallyOrExcept: dest.add "u0" + of sfSingleUsedTemp: dest.add "s3" + of sfNoalias: dest.add "n4" + of sfEffectsDelayed: dest.add "e4" + of sfGeneratedType: dest.add "g2" + of sfVirtual: dest.add "v0" + of sfByCopy: dest.add "b0" + of sfMember: dest.add "m1" + of sfCodegenDecl: dest.add "c5" + of sfWasGenSym: dest.add "w0" + of sfForceLift: dest.add "l" + of sfDirty: dest.add "d3" + of sfCustomPragma: dest.add "c6" + of sfBase: dest.add "b1" + of sfGoto: dest.add "g3" + of sfAnon: dest.add "a0" + of sfAllUntyped: dest.add "a1" + of sfTemplateRedefinition: dest.add "t1" + + +proc parseSymFlags*(s: string): set[TSymFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': + if i+1 < s.len and s[i+1] == '0': + result.incl sfAnon + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfAllUntyped + inc i + else: result.incl sfAddrTaken + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl sfByCopy + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfBase + inc i + else: result.incl sfBorrow + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl sfCppNonPod + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfCompileTime + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfConstructor + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfCallsite + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfCursor + inc i + elif i+1 < s.len and s[i+1] == '5': + result.incl sfCodegenDecl + inc i + elif i+1 < s.len and s[i+1] == '6': + result.incl sfCustomPragma + inc i + else: result.incl sfCompilerProc + of 'd': + if i+1 < s.len and s[i+1] == '0': + result.incl sfDeprecated + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfDispatcher + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfDiscardable + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfDirty + inc i + else: result.incl sfDiscriminant + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl sfExportc + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfEscapes + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfExplain + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfError + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfEffectsDelayed + inc i + else: result.incl sfExported + of 'f': + if i+1 < s.len and s[i+1] == '0': + result.incl sfForward + inc i + else: result.incl sfFromGeneric + of 'g': + if i+1 < s.len and s[i+1] == '0': + result.incl sfGenSym + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfGeneratedOp + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfGeneratedType + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfGoto + inc i + else: result.incl sfGlobal + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl sfInfixCall + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfInjectDestructors + inc i + else: result.incl sfImportc + of 'l': result.incl sfForceLift + of 'm': + if i+1 < s.len and s[i+1] == '0': + result.incl sfMainModule + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfMember + inc i + else: result.incl sfMangleCpp + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl sfNoReturn + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfNamedParamCall + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfNonReloadable + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfNeverRaises + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfNoalias + inc i + else: result.incl sfNoSideEffect + of 'o': result.incl sfOverridden + of 'p': result.incl sfPure + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl sfRequiresInit + inc i + else: result.incl sfRegister + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl sfSystemModule + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfShadowed + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfSystemRaisesDefect + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfSingleUsedTemp + inc i + else: result.incl sfSideEffect + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl sfTemplateParam + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfTemplateRedefinition + inc i + else: result.incl sfThread + of 'u': + if i+1 < s.len and s[i+1] == '0': + result.incl sfUsedInFinallyOrExcept + inc i + else: result.incl sfUsed + of 'v': + if i+1 < s.len and s[i+1] == '0': + result.incl sfVirtual + inc i + else: result.incl sfVolatile + of 'w': + if i+1 < s.len and s[i+1] == '0': + result.incl sfWasGenSym + inc i + else: result.incl sfWasForwarded + else: discard + inc i + +proc genFlags*(s: set[TNodeFlag]; dest: var string) = + for e in s: + case e + of nfNone: dest.add "n" + of nfBase2: dest.add "b" + of nfBase8: dest.add "b0" + of nfBase16: dest.add "b1" + of nfAllConst: dest.add "a" + of nfTransf: dest.add "t" + of nfNoRewrite: dest.add "r" + of nfSem: dest.add "s" + of nfLL: dest.add "l" + of nfDotField: dest.add "d" + of nfDotSetter: dest.add "d0" + of nfExplicitCall: dest.add "e" + of nfExprCall: dest.add "c" + of nfIsRef: dest.add "i" + of nfIsPtr: dest.add "p" + of nfPreventCg: dest.add "p0" + of nfBlockArg: dest.add "b2" + of nfFromTemplate: dest.add "f" + of nfDefaultParam: dest.add "d1" + of nfDefaultRefsParam: dest.add "d2" + of nfExecuteOnReload: dest.add "o" + of nfLastRead: dest.add "l0" + of nfFirstWrite: dest.add "w" + of nfHasComment: dest.add "h" + of nfSkipFieldChecking: dest.add "s0" + of nfDisabledOpenSym: dest.add "d3" + + +proc parseNodeFlags*(s: string): set[TNodeFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': result.incl nfAllConst + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl nfBase8 + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl nfBase16 + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl nfBlockArg + inc i + else: result.incl nfBase2 + of 'c': result.incl nfExprCall + of 'd': + if i+1 < s.len and s[i+1] == '0': + result.incl nfDotSetter + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl nfDefaultParam + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl nfDefaultRefsParam + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl nfDisabledOpenSym + inc i + else: result.incl nfDotField + of 'e': result.incl nfExplicitCall + of 'f': result.incl nfFromTemplate + of 'h': result.incl nfHasComment + of 'i': result.incl nfIsRef + of 'l': + if i+1 < s.len and s[i+1] == '0': + result.incl nfLastRead + inc i + else: result.incl nfLL + of 'n': result.incl nfNone + of 'o': result.incl nfExecuteOnReload + of 'p': + if i+1 < s.len and s[i+1] == '0': + result.incl nfPreventCg + inc i + else: result.incl nfIsPtr + of 'r': result.incl nfNoRewrite + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl nfSkipFieldChecking + inc i + else: result.incl nfSem + of 't': result.incl nfTransf + of 'w': result.incl nfFirstWrite + else: discard + inc i + +proc genFlags*(s: set[TTypeFlag]; dest: var string) = + for e in s: + case e + of tfVarargs: dest.add "v" + of tfNoSideEffect: dest.add "n" + of tfFinal: dest.add "f" + of tfInheritable: dest.add "i" + of tfHasOwned: dest.add "h" + of tfEnumHasHoles: dest.add "e" + of tfShallow: dest.add "s" + of tfThread: dest.add "t" + of tfFromGeneric: dest.add "g" + of tfUnresolved: dest.add "u" + of tfResolved: dest.add "r" + of tfRetType: dest.add "r0" + of tfCapturesEnv: dest.add "c" + of tfByCopy: dest.add "b" + of tfByRef: dest.add "b0" + of tfIterator: dest.add "i0" + of tfPartial: dest.add "p" + of tfNotNil: dest.add "n0" + of tfRequiresInit: dest.add "r1" + of tfNeedsFullInit: dest.add "n1" + of tfVarIsPtr: dest.add "v0" + of tfHasMeta: dest.add "m" + of tfHasGCedMem: dest.add "h0" + of tfPacked: dest.add "p0" + of tfHasStatic: dest.add "h1" + of tfGenericTypeParam: dest.add "g0" + of tfImplicitTypeParam: dest.add "i1" + of tfInferrableStatic: dest.add "i2" + of tfConceptMatchedTypeSym: dest.add "c0" + of tfExplicit: dest.add "e0" + of tfWildcard: dest.add "w" + of tfHasAsgn: dest.add "a" + of tfBorrowDot: dest.add "d" + of tfTriggersCompileTime: dest.add "t0" + of tfRefsAnonObj: dest.add "o" + of tfCovariant: dest.add "c1" + of tfWeakCovariant: dest.add "w0" + of tfContravariant: dest.add "c2" + of tfCheckedForDestructor: dest.add "c3" + of tfAcyclic: dest.add "a0" + of tfIncompleteStruct: dest.add "i3" + of tfCompleteStruct: dest.add "c4" + of tfExplicitCallConv: dest.add "e1" + of tfIsConstructor: dest.add "i4" + of tfEffectSystemWorkaround: dest.add "e2" + of tfIsOutParam: dest.add "i5" + of tfSendable: dest.add "s0" + of tfImplicitStatic: dest.add "i6" + + +proc parseTypeFlags*(s: string): set[TTypeFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': + if i+1 < s.len and s[i+1] == '0': + result.incl tfAcyclic + inc i + else: result.incl tfHasAsgn + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl tfByRef + inc i + else: result.incl tfByCopy + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl tfConceptMatchedTypeSym + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfCovariant + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfContravariant + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl tfCheckedForDestructor + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl tfCompleteStruct + inc i + else: result.incl tfCapturesEnv + of 'd': result.incl tfBorrowDot + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl tfExplicit + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfExplicitCallConv + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfEffectSystemWorkaround + inc i + else: result.incl tfEnumHasHoles + of 'f': result.incl tfFinal + of 'g': + if i+1 < s.len and s[i+1] == '0': + result.incl tfGenericTypeParam + inc i + else: result.incl tfFromGeneric + of 'h': + if i+1 < s.len and s[i+1] == '0': + result.incl tfHasGCedMem + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfHasStatic + inc i + else: result.incl tfHasOwned + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl tfIterator + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfImplicitTypeParam + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfInferrableStatic + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl tfIncompleteStruct + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl tfIsConstructor + inc i + elif i+1 < s.len and s[i+1] == '5': + result.incl tfIsOutParam + inc i + elif i+1 < s.len and s[i+1] == '6': + result.incl tfImplicitStatic + inc i + else: result.incl tfInheritable + of 'm': result.incl tfHasMeta + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl tfNotNil + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfNeedsFullInit + inc i + else: result.incl tfNoSideEffect + of 'o': result.incl tfRefsAnonObj + of 'p': + if i+1 < s.len and s[i+1] == '0': + result.incl tfPacked + inc i + else: result.incl tfPartial + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl tfRetType + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfRequiresInit + inc i + else: result.incl tfResolved + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl tfSendable + inc i + else: result.incl tfShallow + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl tfTriggersCompileTime + inc i + else: result.incl tfThread + of 'u': result.incl tfUnresolved + of 'v': + if i+1 < s.len and s[i+1] == '0': + result.incl tfVarIsPtr + inc i + else: result.incl tfVarargs + of 'w': + if i+1 < s.len and s[i+1] == '0': + result.incl tfWeakCovariant + inc i + else: result.incl tfWildcard + else: discard + inc i + +proc genFlags*(s: set[TLocFlag]; dest: var string) = + for e in s: + case e + of lfIndirect: dest.add "i" + of lfNoDeepCopy: dest.add "n" + of lfNoDecl: dest.add "d" + of lfDynamicLib: dest.add "l" + of lfExportLib: dest.add "e" + of lfHeader: dest.add "h" + of lfImportCompilerProc: dest.add "c" + of lfSingleUse: dest.add "s" + of lfEnforceDeref: dest.add "e0" + of lfPrepareForMutation: dest.add "p" + + +proc parseLocFlags*(s: string): set[TLocFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'c': result.incl lfImportCompilerProc + of 'd': result.incl lfNoDecl + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl lfEnforceDeref + inc i + else: result.incl lfExportLib + of 'h': result.incl lfHeader + of 'i': result.incl lfIndirect + of 'l': result.incl lfDynamicLib + of 'n': result.incl lfNoDeepCopy + of 'p': result.incl lfPrepareForMutation + of 's': result.incl lfSingleUse + else: discard + inc i + +proc genFlags*(s: set[TOption]; dest: var string) = + for e in s: + case e + of optNone: dest.add "n" + of optObjCheck: dest.add "o" + of optFieldCheck: dest.add "f" + of optRangeCheck: dest.add "r" + of optBoundsCheck: dest.add "b" + of optOverflowCheck: dest.add "c" + of optRefCheck: dest.add "r0" + of optNaNCheck: dest.add "n0" + of optInfCheck: dest.add "i" + of optStaticBoundsCheck: dest.add "s" + of optStyleCheck: dest.add "s0" + of optAssert: dest.add "a" + of optLineDir: dest.add "l" + of optWarns: dest.add "w" + of optHints: dest.add "h" + of optOptimizeSpeed: dest.add "o0" + of optOptimizeSize: dest.add "o1" + of optStackTrace: dest.add "t" + of optStackTraceMsgs: dest.add "m" + of optLineTrace: dest.add "l0" + of optByRef: dest.add "b0" + of optProfiler: dest.add "p" + of optImplicitStatic: dest.add "i0" + of optTrMacros: dest.add "t0" + of optMemTracker: dest.add "m0" + of optSinkInference: dest.add "s1" + of optCursorInference: dest.add "c0" + of optImportHidden: dest.add "i1" + of optQuirky: dest.add "q" + + +proc parseOptions*(s: string): set[TOption] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': result.incl optAssert + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl optByRef + inc i + else: result.incl optBoundsCheck + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl optCursorInference + inc i + else: result.incl optOverflowCheck + of 'f': result.incl optFieldCheck + of 'h': result.incl optHints + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl optImplicitStatic + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optImportHidden + inc i + else: result.incl optInfCheck + of 'l': + if i+1 < s.len and s[i+1] == '0': + result.incl optLineTrace + inc i + else: result.incl optLineDir + of 'm': + if i+1 < s.len and s[i+1] == '0': + result.incl optMemTracker + inc i + else: result.incl optStackTraceMsgs + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl optNaNCheck + inc i + else: result.incl optNone + of 'o': + if i+1 < s.len and s[i+1] == '0': + result.incl optOptimizeSpeed + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optOptimizeSize + inc i + else: result.incl optObjCheck + of 'p': result.incl optProfiler + of 'q': result.incl optQuirky + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl optRefCheck + inc i + else: result.incl optRangeCheck + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl optStyleCheck + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optSinkInference + inc i + else: result.incl optStaticBoundsCheck + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl optTrMacros + inc i + else: result.incl optStackTrace + of 'w': result.incl optWarns + else: discard + inc i + diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim new file mode 100644 index 0000000000000..aaa5a3a8dcee4 --- /dev/null +++ b/compiler/icnif/nifdecoder.nim @@ -0,0 +1,105 @@ +import std / [assertions, tables] +import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors] +import ".." / [ast, astalgo, idents, lineinfos, options, modulegraphs, pathutils] +import enum2nif + +type + DecodeContext = object + graph: ModuleGraph + +proc nodeKind(n: Cursor): TNodeKind {.inline.} = + assert n.kind == ParLe + pool.tags[n.tagId].parseNodeKind() + +var sysTypes: Table[TTypeKind, PType] + +proc getSysType(typeKind: TTypeKind): PType = + # This will be replaced with magicsys.getSysType + assert typeKind in {tyBool, tyChar, tyInt .. tyUInt64} + if typeKind in sysTypes: + result = sysTypes[typeKind] + else: + result = PType(itemId: ItemId(module: 0, item: typeKind.int32), kind: typeKind) + +proc fromNif(c: var DecodeContext; n: var Cursor): PNode + +proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = + result = newNodeI(kind, unknownLineInfo, 1) + inc n + assert n.nodeKind == nkIdentDefs + result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) + inc n + assert n.nodeKind == nkSym + let symKind = case kind: + of nkVarSection: skVar + of nkLetSection: skLet + else: skConst + inc n + assert n.kind == Ident + let ident = c.graph.cache.getIdent(pool.strings[n.litId]) + inc n + assert n.kind == IntLit + let id = pool.integers[n.intId] + result[0][0] = PSym(itemId: ItemId(module: 0, item: id.int32), kind: symKind, name: ident).newSymNode() + inc n + assert n.kind == ParRi + inc n + result[0][1] = fromNif(c, n) + result[0][2] = fromNif(c, n) + assert n.kind == ParRi + inc n + assert n.kind == ParRi + inc n + +proc fromNif(c: var DecodeContext; n: var Cursor): PNode = + result = nil + case n.kind: + of DotToken: + result = newNode(nkEmpty) + inc n + of IntLit: + result = newIntTypeNode(pool.integers[n.intId], getSysType(tyInt)) + inc n + of ParLe: + let kind = n.nodeKind + case kind: + of nkStmtList: + result = newNode(nkStmtList) + inc n + while n.kind != ParRi: + result.add fromNif(c, n) + inc n + of nkVarSection, nkLetSection: + result = fromNifLocal(c, n, kind) + else: + assert false, "Not yet implemented " & $kind + else: + assert false, "Not yet implemented " & $n.kind + +proc loadNif(stream: var Stream; graph: ModuleGraph): PNode = + discard processDirectives(stream.r) + + var buf = fromStream(stream) + var n = beginRead(buf) + + var c = DecodeContext(graph: graph) + result = fromNif(c, n) + + endRead(buf) + +proc loadNifFile*(infile: AbsoluteFile; graph: ModuleGraph): PNode = + var stream = nifstreams.open(infile.string) + result = loadNif(stream, graph) + stream.close + +proc loadNifFromBuffer*(strbuf: sink string; graph: ModuleGraph): PNode = + var stream = nifstreams.openFromBuffer(strbuf) + result = loadNif(stream, graph) + +when isMainModule: + import std/cmdline + + if paramCount() > 0: + var graph = newModuleGraph(newIdentCache(), newConfigRef()) + var node = loadNifFile(paramStr(1).AbsoluteFile, graph) + debug(node) diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim new file mode 100644 index 0000000000000..a447520fcce77 --- /dev/null +++ b/compiler/icnif/nifencoder.nim @@ -0,0 +1,56 @@ +import std / [assertions] +import ".." / [ast, astalgo, idents] +import "../../dist/nimony/src/lib" / nifbuilder +import enum2nif + +type + EncodeContext = object + b: Builder + +proc toNifSymDef(c: var EncodeContext; n: PNode) = + assert n.kind == nkSym + let sym = n.sym + c.b.addTree toNifTag(n.kind) + c.b.addIdent sym.name.s + c.b.addIntLit sym.itemId.item + c.b.endTree() + +proc toNif(c: var EncodeContext; n: PNode) = + case n.kind: + of nkEmpty: + c.b.addEmpty() + of nkIntLit: + c.b.addIntLit n.intVal + of nkIdentDefs: + c.b.addTree toNifTag(n.kind) + assert n.len == 3 + toNifSymDef(c, n[0]) + toNif c, n[1] + toNif c, n[2] + c.b.endTree() + else: + assert n.len > 0, $n.kind + c.b.addTree toNifTag(n.kind) + for i in 0 ..< n.len: + toNif c, n[i] + c.b.endTree() + +proc saveNif(c: var EncodeContext; n: PNode) = + c.b.addHeader "nim2", "nim2-ic-nif" + c.b.addTree "stmts" + assert n.kind == nkStmtList + for i in 0 ..< n.len: + toNif c, n[i] + c.b.endTree() + +proc saveNifFile*(module: PSym; n: PNode) = + let outfile = module.name.s & ".nif" + var c = EncodeContext(b: nifbuilder.open(outfile)) + saveNif(c, n) + c.b.close() + +proc saveNifToBuffer*(n: PNode): string = + var c = EncodeContext(b: nifbuilder.open(100)) + saveNif(c, n) + c.b.close() + result = c.b.extract diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index e617ae8b90b0c..d3d740334194d 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -13,6 +13,7 @@ when not defined(leanCompiler): import std/[syncio, objectdollar, assertions, tables, strutils, strtabs] import renderer import ic/replayer +import icnif/nifencoder, astalgo proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) = graph.pipelinePass = pass @@ -182,6 +183,13 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator message(graph.config, sl.info, hintProcessingStmt, $idgen[]) var semNode = semWithPContext(ctx, sl) discard processPipeline(graph, semNode, bModule) + when false: + # encode the asts of specific modules to NIF files for debug or tests. + if module.name.s.substr(0, 3) == "test": + echo "saveNifFile: ", module.name.s + echo "n:" + debug(n) + nifencoder.saveNifFile(module, semNode) closeParser(p) if s.kind != llsStdIn: break diff --git a/tests/icnif/tencode.nim b/tests/icnif/tencode.nim new file mode 100644 index 0000000000000..83e6e329617e3 --- /dev/null +++ b/tests/icnif/tencode.nim @@ -0,0 +1,20 @@ +import std/assertions +import "../../compiler/icnif" / [nifencoder, nifdecoder] +import "../../compiler" / [idents, options, modulegraphs] + +var graph = newModuleGraph(newIdentCache(), newConfigRef()) + +block: + const TestNif = """ +(.nif24) +(.vendor "nim2") +(.dialect "nim2-ic-nif") +(stmts + (var + (identdefs + (sym x +1) . +123)) + (var + (identdefs + (sym y +2) . +321)))""" + + assert loadNifFromBuffer(TestNif, graph).saveNifToBuffer() == TestNif From 04a0bbe6743f0b41a78a544f096b5250efd4b996 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sat, 4 Oct 2025 17:51:46 +0900 Subject: [PATCH 02/21] encodes Nim PSym to NIF Symbol and SymbolDef --- compiler/icnif/nifdecoder.nim | 88 ++++++++++++++++++++++++++++------ compiler/icnif/nifencoder.nim | 89 +++++++++++++++++++++++++++++------ compiler/pipelines.nim | 6 +-- tests/icnif/tencode.nim | 24 +++++----- 4 files changed, 163 insertions(+), 44 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index aaa5a3a8dcee4..a4f5ebfa0a467 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -1,11 +1,12 @@ -import std / [assertions, tables] -import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors] -import ".." / [ast, astalgo, idents, lineinfos, options, modulegraphs, pathutils] +import std / [assertions, tables, parseutils] +import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors, symparser] +import ".." / [ast, astalgo, idents, lineinfos, options, modulegraphs, msgs, pathutils] import enum2nif type DecodeContext = object graph: ModuleGraph + nifSymToPSym: Table[string, PSym] # foo.1.modsuffix -> PSym proc nodeKind(n: Cursor): TNodeKind {.inline.} = assert n.kind == ParLe @@ -21,36 +22,87 @@ proc getSysType(typeKind: TTypeKind): PType = else: result = PType(itemId: ItemId(module: 0, item: typeKind.int32), kind: typeKind) +type + SplittedNifSym = object + name: string + id: int + module: string + +proc splitNifSym(s: string): SplittedNifSym = + result = SplittedNifSym() + var i = s.len - 2 + var mp = -1 + while i > 0: + if s[i] == '.': + if s[i+1] in {'0'..'9'}: + var id = 0 + discard parseutils.parseInt(s, id, i + 1) + return SplittedNifSym( + name: s.substr(0, i - 1), + id: id, + module: if mp < 0: "" else: s.substr(mp, s.high)) + else: + mp = i + 1 + dec i + proc fromNif(c: var DecodeContext; n: var Cursor): PNode -proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = - result = newNodeI(kind, unknownLineInfo, 1) - inc n - assert n.nodeKind == nkIdentDefs - result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) - inc n +proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = assert n.nodeKind == nkSym let symKind = case kind: of nkVarSection: skVar of nkLetSection: skLet + of nkImportStmt: skModule else: skConst inc n - assert n.kind == Ident - let ident = c.graph.cache.getIdent(pool.strings[n.litId]) + assert n.kind == SymbolDef + let nifSym = pool.syms[n.symId] + let symdef = nifSym.splitNifSym + assert symdef.name.len != 0 + let ident = c.graph.cache.getIdent(symdef.name) + inc n + assert n.kind in {Ident, DotToken}, $n.kind + let flags = if n.kind == Ident: pool.strings[n.litId].parseSymFlags else: {} inc n - assert n.kind == IntLit - let id = pool.integers[n.intId] - result[0][0] = PSym(itemId: ItemId(module: 0, item: id.int32), kind: symKind, name: ident).newSymNode() + var position = 0 + if symKind == skModule: + assert n.kind == StringLit + let path = pool.strings[n.litId].AbsoluteFile + position = fileInfoIdx(c.graph.config, path).int + else: + assert n.kind == IntLit + position = pool.integers[n.intId] inc n + + let psym = PSym(itemId: ItemId(module: 0, item: symdef.id.int32), kind: symKind, name: ident, flags: flags, position: position) + result = newSymNode(psym) + let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSym, psym) + assert not hasSym + assert n.kind == ParRi inc n + +proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = + result = newNodeI(kind, unknownLineInfo, 1) + inc n + assert n.nodeKind == nkIdentDefs + result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) + inc n + result[0][0] = fromNifSymDef(c, n, kind) result[0][1] = fromNif(c, n) result[0][2] = fromNif(c, n) - assert n.kind == ParRi + assert n.kind == ParRi # nkIdentDefs inc n assert n.kind == ParRi inc n +proc fromNifImport(c: var DecodeContext; n: var Cursor): PNode = + result = newNode(nkImportStmt) + inc n + while n.kind != ParRi: + result.add fromNifSymDef(c, n, nkImportStmt) + inc n + proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = nil case n.kind: @@ -60,6 +112,10 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = of IntLit: result = newIntTypeNode(pool.integers[n.intId], getSysType(tyInt)) inc n + of Symbol: + let sym = c.nifSymToPSym[pool.syms[n.symId]] + result = newSymNode(sym) + inc n of ParLe: let kind = n.nodeKind case kind: @@ -71,6 +127,8 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = inc n of nkVarSection, nkLetSection: result = fromNifLocal(c, n, kind) + of nkImportStmt: + result = fromNifImport(c, n) else: assert false, "Not yet implemented " & $kind else: diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index a447520fcce77..9091bc8f756a6 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -1,18 +1,63 @@ -import std / [assertions] -import ".." / [ast, astalgo, idents] +import std / [assertions, tables] +import ".." / [ast, astalgo, idents, lineinfos, msgs, options] import "../../dist/nimony/src/lib" / nifbuilder +import "../../dist/nimony/src/gear2" / modnames import enum2nif type EncodeContext = object b: Builder + conf: ConfigRef + toSuffix: Table[FileIndex, string] + moduleToNifSuffix: Table[ItemId, string] # module PSym -> module suffix -proc toNifSymDef(c: var EncodeContext; n: PNode) = +proc modname(c: var EncodeContext; idx: FileIndex): string = + # copied from ../nifgen.nim + 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 toNifSym(c: var EncodeContext; sym: PSym): string = + result = sym.name.s & '.' & $sym.itemId.item + if sym.owner.kind == skModule: + result.add '.' + var modsuf = c.moduleToNifSuffix.getOrDefault(sym.owner.itemId) + if modsuf.len == 0: + modsuf = modname(c, sym.owner.position.FileIndex) + c.moduleToNifSuffix[sym.owner.itemId] = modsuf + result.add modsuf + +proc symdefToNif(c: var EncodeContext; n: PNode) = assert n.kind == nkSym let sym = n.sym c.b.addTree toNifTag(n.kind) - c.b.addIdent sym.name.s - c.b.addIntLit sym.itemId.item + var name = toNifSym(c, sym) + c.b.addSymbolDef name + if sym.flags == {}: + c.b.addEmpty() + else: + var flags: string = "" + genFlags(sym.flags, flags) + c.b.addIdent flags + if sym.kind == skModule: + # position is module's FileIndex but it cannot be directly encoded + # as the uniqueness of it can broke + # if any import/include statements are changed. + let path = toFullPath(c.conf, sym.position.FileIndex) + c.b.addStrLit path + else: + c.b.addIntLit sym.position + c.b.endTree() + +proc toNifImport(c: var EncodeContext; n: PNode) = + c.b.addTree toNifTag(n.kind) + for i in 0 ..< n.len: + assert n[i].kind == nkSym + let sym = n[i].sym + assert sym.kind == skModule + symdefToNif(c, n[i]) c.b.endTree() proc toNif(c: var EncodeContext; n: PNode) = @@ -24,10 +69,28 @@ proc toNif(c: var EncodeContext; n: PNode) = of nkIdentDefs: c.b.addTree toNifTag(n.kind) assert n.len == 3 - toNifSymDef(c, n[0]) + symdefToNif(c, n[0]) toNif c, n[1] toNif c, n[2] c.b.endTree() + of nkSym: + when false: + echo "nkSym: ", n.sym.name.s + if n.sym.kind == skModule: + echo "position = ", n.sym.position + debug(n.sym) + var o = n.sym.owner + for i in 0 .. 20: + if o == nil: + break + echo "owner ", i, ":" + if o.kind == skModule: + echo "position = ", o.position + debug(o) + o = o.owner + c.b.addSymbol toNifSym(c, n.sym) + of nkImportStmt: + toNifImport(c, n) else: assert n.len > 0, $n.kind c.b.addTree toNifTag(n.kind) @@ -37,20 +100,16 @@ proc toNif(c: var EncodeContext; n: PNode) = proc saveNif(c: var EncodeContext; n: PNode) = c.b.addHeader "nim2", "nim2-ic-nif" - c.b.addTree "stmts" - assert n.kind == nkStmtList - for i in 0 ..< n.len: - toNif c, n[i] - c.b.endTree() + toNif c, n -proc saveNifFile*(module: PSym; n: PNode) = +proc saveNifFile*(module: PSym; n: PNode; conf: ConfigRef) = let outfile = module.name.s & ".nif" - var c = EncodeContext(b: nifbuilder.open(outfile)) + var c = EncodeContext(b: nifbuilder.open(outfile), conf: conf) saveNif(c, n) c.b.close() -proc saveNifToBuffer*(n: PNode): string = - var c = EncodeContext(b: nifbuilder.open(100)) +proc saveNifToBuffer*(n: PNode; conf: ConfigRef): string = + var c = EncodeContext(b: nifbuilder.open(100), conf: conf) saveNif(c, n) c.b.close() result = c.b.extract diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index d3d740334194d..1d9d7f599dd02 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -187,9 +187,9 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator # encode the asts of specific modules to NIF files for debug or tests. if module.name.s.substr(0, 3) == "test": echo "saveNifFile: ", module.name.s - echo "n:" - debug(n) - nifencoder.saveNifFile(module, semNode) + echo "semNode:" + debug(semNode) + nifencoder.saveNifFile(module, semNode, graph.config) closeParser(p) if s.kind != llsStdIn: break diff --git a/tests/icnif/tencode.nim b/tests/icnif/tencode.nim index 83e6e329617e3..285a84fd2835a 100644 --- a/tests/icnif/tencode.nim +++ b/tests/icnif/tencode.nim @@ -6,15 +6,17 @@ var graph = newModuleGraph(newIdentCache(), newConfigRef()) block: const TestNif = """ -(.nif24) -(.vendor "nim2") -(.dialect "nim2-ic-nif") -(stmts - (var - (identdefs - (sym x +1) . +123)) - (var - (identdefs - (sym y +2) . +321)))""" + (.nif24) + (.vendor "nim2") + (.dialect "nim2-ic-nif") + (stmts + (import + (sym :testmod2.1 . "/home/nimdev/testnim/testmod2.nim")) + (var + (identdefs + (sym :x.2.tesvp2f3v ueg +0) . +123)) + (var + (identdefs + (sym :y.3.tesvp2f3v g +0) . x.2.tesvp2f3v)))""" - assert loadNifFromBuffer(TestNif, graph).saveNifToBuffer() == TestNif + assert loadNifFromBuffer(TestNif, graph).saveNifToBuffer(graph.config) == TestNif From b3833a3454d3e2c97c485bed4ad2a2bd9eaa247e Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Mon, 6 Oct 2025 20:28:28 +0900 Subject: [PATCH 03/21] encodes/decodes symbol's owner --- compiler/icnif/nifdecoder.nim | 61 ++++++++++++++++++++++++----------- compiler/icnif/nifencoder.nim | 24 ++++++++++---- tests/icnif/tencode.nim | 29 +++++++++-------- 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index a4f5ebfa0a467..051da61022545 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -1,6 +1,7 @@ import std / [assertions, tables, parseutils] -import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors, symparser] -import ".." / [ast, astalgo, idents, lineinfos, options, modulegraphs, msgs, pathutils] +import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors] +import ".." / [ast, astalgo, idents, lineinfos, options, modules, modulegraphs, msgs, pathutils] +import "../../dist/nimony/src/gear2" / modnames import enum2nif type @@ -47,6 +48,10 @@ proc splitNifSym(s: string): SplittedNifSym = proc fromNif(c: var DecodeContext; n: var Cursor): PNode +proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = + result = c.nifSymToPSym[pool.syms[n.symId]] + inc n + proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = assert n.nodeKind == nkSym let symKind = case kind: @@ -61,20 +66,34 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode assert symdef.name.len != 0 let ident = c.graph.cache.getIdent(symdef.name) inc n + assert n.kind == IntLit + let itemId = pool.integers[n.intId].int32 + inc n + assert n.kind in {Symbol, DotToken}, $n.kind + let owner = if n.kind == Symbol: + fromNifSymbol(c, n) + else: + inc n + nil assert n.kind in {Ident, DotToken}, $n.kind let flags = if n.kind == Ident: pool.strings[n.litId].parseSymFlags else: {} inc n - var position = 0 - if symKind == skModule: - assert n.kind == StringLit - let path = pool.strings[n.litId].AbsoluteFile - position = fileInfoIdx(c.graph.config, path).int - else: - assert n.kind == IntLit - position = pool.integers[n.intId] + var position = if symKind == skModule: + assert n.kind == StringLit + let path = pool.strings[n.litId].AbsoluteFile + fileInfoIdx(c.graph.config, path).int + else: + assert n.kind == IntLit + pool.integers[n.intId] inc n - let psym = PSym(itemId: ItemId(module: 0, item: symdef.id.int32), kind: symKind, name: ident, flags: flags, position: position) + var psym = PSym(itemId: ItemId(module: 0, item: itemId), + kind: symKind, + name: ident, + flags: flags, + position: position, + disamb: symdef.id.int32) + psym.setOwner(owner) result = newSymNode(psym) let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSym, psym) assert not hasSym @@ -113,9 +132,7 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = newIntTypeNode(pool.integers[n.intId], getSysType(tyInt)) inc n of Symbol: - let sym = c.nifSymToPSym[pool.syms[n.symId]] - result = newSymNode(sym) - inc n + result = newSymNode(fromNifSymbol(c, n)) of ParLe: let kind = n.nodeKind case kind: @@ -134,30 +151,36 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = else: assert false, "Not yet implemented " & $n.kind -proc loadNif(stream: var Stream; graph: ModuleGraph): PNode = +proc loadNif(stream: var Stream; modulePath: AbsoluteFile; graph: ModuleGraph): PNode = discard processDirectives(stream.r) var buf = fromStream(stream) var n = beginRead(buf) var c = DecodeContext(graph: graph) + + let modSym = newModule(graph, fileInfoIdx(graph.config, modulePath)) + let modSuffix = moduleSuffix(modulePath.string, cast[seq[string]](graph.config.searchPaths)) + let nifModSym = modSym.name.s & '.' & $modSym.disamb & '.' & modSuffix + c.nifSymToPSym[nifModSym] = modSym + result = fromNif(c, n) endRead(buf) proc loadNifFile*(infile: AbsoluteFile; graph: ModuleGraph): PNode = var stream = nifstreams.open(infile.string) - result = loadNif(stream, graph) + result = loadNif(stream, infile.changeFileExt("nim"), graph) stream.close -proc loadNifFromBuffer*(strbuf: sink string; graph: ModuleGraph): PNode = +proc loadNifFromBuffer*(strbuf: sink string; modulePath: AbsoluteFile; graph: ModuleGraph): PNode = var stream = nifstreams.openFromBuffer(strbuf) - result = loadNif(stream, graph) + result = loadNif(stream, modulePath, graph) when isMainModule: import std/cmdline if paramCount() > 0: var graph = newModuleGraph(newIdentCache(), newConfigRef()) - var node = loadNifFile(paramStr(1).AbsoluteFile, graph) + var node = loadNifFile(paramStr(1).toAbsolute(toAbsoluteDir(".")), graph) debug(node) diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 9091bc8f756a6..ca19f0fee8139 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -9,7 +9,7 @@ type b: Builder conf: ConfigRef toSuffix: Table[FileIndex, string] - moduleToNifSuffix: Table[ItemId, string] # module PSym -> module suffix + moduleToNifSuffix: Table[FileIndex, string] # FileIndex (PSym.position) -> module suffix proc modname(c: var EncodeContext; idx: FileIndex): string = # copied from ../nifgen.nim @@ -20,21 +20,31 @@ proc modname(c: var EncodeContext; idx: FileIndex): string = c.toSuffix[idx] = result proc toNifSym(c: var EncodeContext; sym: PSym): string = - result = sym.name.s & '.' & $sym.itemId.item - if sym.owner.kind == skModule: + result = sym.name.s & '.' & $sym.disamb + let owner = sym.skipGenericOwner() + if owner.kind == skModule: result.add '.' - var modsuf = c.moduleToNifSuffix.getOrDefault(sym.owner.itemId) + let fileIndex = FileIndex owner.position + var modsuf = c.moduleToNifSuffix.getOrDefault(fileIndex) if modsuf.len == 0: - modsuf = modname(c, sym.owner.position.FileIndex) - c.moduleToNifSuffix[sym.owner.itemId] = modsuf + modsuf = modname(c, fileIndex) + c.moduleToNifSuffix[fileIndex] = modsuf result.add modsuf +proc symToNif(c: var EncodeContext; sym: PSym) = + c.b.addSymbol toNifSym(c, sym) + proc symdefToNif(c: var EncodeContext; n: PNode) = assert n.kind == nkSym let sym = n.sym c.b.addTree toNifTag(n.kind) var name = toNifSym(c, sym) c.b.addSymbolDef name + c.b.addIntLit sym.itemId.item + if sym.owner == nil or sym.owner.kind == skPackage: + c.b.addEmpty + else: + symToNif(c, sym.owner) if sym.flags == {}: c.b.addEmpty() else: @@ -88,7 +98,7 @@ proc toNif(c: var EncodeContext; n: PNode) = echo "position = ", o.position debug(o) o = o.owner - c.b.addSymbol toNifSym(c, n.sym) + symToNif(c, n.sym) of nkImportStmt: toNifImport(c, n) else: diff --git a/tests/icnif/tencode.nim b/tests/icnif/tencode.nim index 285a84fd2835a..6f83e12d751c4 100644 --- a/tests/icnif/tencode.nim +++ b/tests/icnif/tencode.nim @@ -1,22 +1,23 @@ import std/assertions import "../../compiler/icnif" / [nifencoder, nifdecoder] -import "../../compiler" / [idents, options, modulegraphs] +import "../../compiler" / [idents, options, pathutils, modulegraphs] var graph = newModuleGraph(newIdentCache(), newConfigRef()) +graph.config.searchPaths.add AbsoluteDir "/tmp/testnim" block: const TestNif = """ - (.nif24) - (.vendor "nim2") - (.dialect "nim2-ic-nif") - (stmts - (import - (sym :testmod2.1 . "/home/nimdev/testnim/testmod2.nim")) - (var - (identdefs - (sym :x.2.tesvp2f3v ueg +0) . +123)) - (var - (identdefs - (sym :y.3.tesvp2f3v g +0) . x.2.tesvp2f3v)))""" +(.nif24) +(.vendor "nim2") +(.dialect "nim2-ic-nif") +(stmts + (import + (sym :testmod2.0.tesfd9rxn1 +1 . . "/tmp/testnim/testmod2.nim")) + (var + (identdefs + (sym :x.0.tesvp2f3v +2 testmod.0.tesvp2f3v ueg +0) . +123)) + (var + (identdefs + (sym :y.0.tesvp2f3v +3 testmod.0.tesvp2f3v g +0) . x.0.tesvp2f3v)))""" - assert loadNifFromBuffer(TestNif, graph).saveNifToBuffer(graph.config) == TestNif + assert loadNifFromBuffer(TestNif, AbsoluteFile"/tmp/testnim/testmod.nim", graph).saveNifToBuffer(graph.config) == TestNif From f46adcf34de1825dea8f7150aa366abadcb8c3cc Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Tue, 7 Oct 2025 19:08:47 +0900 Subject: [PATCH 04/21] adds test --- tests/icnif/tencode_node2node.nim | 113 ++++++++++++++++++++++++++++++ tests/icnif/testcode/testmod.nim | 2 + 2 files changed, 115 insertions(+) create mode 100644 tests/icnif/tencode_node2node.nim create mode 100644 tests/icnif/testcode/testmod.nim diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim new file mode 100644 index 0000000000000..40f7c5c9c74ca --- /dev/null +++ b/tests/icnif/tencode_node2node.nim @@ -0,0 +1,113 @@ +import std/assertions +import "../../compiler/icnif" / [nifencoder, nifdecoder] +import "../../compiler" / [idents, ast, astalgo, options, pathutils, modulegraphs, modules, msgs, pipelines, syntaxes, sem, llstream, lineinfos] + +const TestCodeDir = currentSourcePath().AbsoluteFile.splitFile().dir / RelativeDir"testcode" + +proc newConfigRefForTest(): ConfigRef = + var conf = newConfigRef() + conf.setDefaultLibpath() + conf.searchPaths.add(conf.libpath) + result = conf + +proc newModuleGraphForSem(cache: IdentCache; conf: ConfigRef): ModuleGraph = + var graph = newModuleGraph(cache, conf) + graph.setPipeLinePass(SemPass) + graph.compilePipelineSystemModule() + result = graph + +proc sem(graph: ModuleGraph; path: AbsoluteFile): PNode = + result = nil + + let fileIdx = fileInfoIdx(graph.config, path) + var module = newModule(graph, fileIdx) + registerModule(graph, module) + + var idgen = idGeneratorFromModule(module) + let ctx = preparePContext(graph, module, idgen) + + var stream = llStreamOpen(path, fmRead) + if stream == nil: + rawMessage(graph.config, errCannotOpenFile, path.string) + return nil + + var p: Parser = default(Parser) + syntaxes.openParser(p, fileIdx, stream, graph.cache, graph.config) + + checkFirstLineIndentation(p) + block processCode: + if graph.stopCompile(): break processCode + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break processCode + # read everything, no streaming possible + var sl = newNodeI(nkStmtList, n.info) + sl.add n + while true: + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break + sl.add n + + var semNode = semWithPContext(ctx, sl) + + return semNode + +# Compare PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support +proc eql(x, y: PSym): bool = + if x == nil and y == nil: + result = true + elif x == nil or y == nil: + result = false + elif x.itemId.item == y.itemId.item and x.kind == y.kind and x.name.s == y.name.s and x.flags == y.flags and x.disamb == y.disamb: + if x.owner == nil and y.owner == nil: + result = true + elif x.owner == nil or y.owner == nil: + result = false + elif x.owner.kind == y.owner.kind and x.owner.name.s == y.owner.name.s: + if x.kind == skModule: + result = true + else: + result = x.position == y.position + else: + result = false + else: + result = false + +proc eql(x, y: PNode): bool = + if x == nil and y == nil: + result = true + elif x == nil or y == nil: + result = false + elif x.kind == y.kind and x.safeLen == y.safeLen: + case x.kind: + of nkSym: + result = eql(x.sym, y.sym) + if not result: + echo "Symbol mismatch:" + #debug(x) + #debug(y) + of nkCharLit .. nkTripleStrLit: + result = sameValue(x, y) + else: + result = true + for i in 0 ..< x.safeLen: + if not eql(x[i], y[i]): + result = false + break + else: + result = false + +proc testNifEncDec(graph: ModuleGraph; src: string) = + let fullPath = TestCodeDir / RelativeFile("testmod.nim") + let n = sem(graph, fullPath) + let nif = saveNifToBuffer(n, graph.config) + # Don't reuse the ModuleGraph used for semcheck when load NIF. + var graphForLoad = newModuleGraph(newIdentCache(), newConfigRefForTest()) + let n2 = loadNifFromBuffer(nif, fullPath, graphForLoad) + #debug(n) + #debug(n2) + assert eql(n, n2) + +var conf = newConfigRefForTest() +var cache = newIdentCache() +var graph = newModuleGraphForSem(cache, conf) +testNifEncDec(graph, "testmod.nim") diff --git a/tests/icnif/testcode/testmod.nim b/tests/icnif/testcode/testmod.nim new file mode 100644 index 0000000000000..f36fa1afd2393 --- /dev/null +++ b/tests/icnif/testcode/testmod.nim @@ -0,0 +1,2 @@ +var x* = 123 +var y = x From be109b103bad15711982f84b2cd23f7bd2c3d2d8 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Tue, 7 Oct 2025 23:30:42 +0900 Subject: [PATCH 05/21] changes test file name --- tests/icnif/tencode_node2node.nim | 4 ++-- tests/icnif/testcode/{testmod.nim => modtest1.nim} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/icnif/testcode/{testmod.nim => modtest1.nim} (100%) diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 40f7c5c9c74ca..09cd9ec63407d 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -97,7 +97,7 @@ proc eql(x, y: PNode): bool = result = false proc testNifEncDec(graph: ModuleGraph; src: string) = - let fullPath = TestCodeDir / RelativeFile("testmod.nim") + let fullPath = TestCodeDir / RelativeFile(src) let n = sem(graph, fullPath) let nif = saveNifToBuffer(n, graph.config) # Don't reuse the ModuleGraph used for semcheck when load NIF. @@ -110,4 +110,4 @@ proc testNifEncDec(graph: ModuleGraph; src: string) = var conf = newConfigRefForTest() var cache = newIdentCache() var graph = newModuleGraphForSem(cache, conf) -testNifEncDec(graph, "testmod.nim") +testNifEncDec(graph, "modtest1.nim") diff --git a/tests/icnif/testcode/testmod.nim b/tests/icnif/testcode/modtest1.nim similarity index 100% rename from tests/icnif/testcode/testmod.nim rename to tests/icnif/testcode/modtest1.nim From d365b0b8a3dcf2620796e2e316aae13416dd0afd Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 8 Oct 2025 18:32:35 +0900 Subject: [PATCH 06/21] supports string/char/int/uint/float literals --- compiler/icnif/nifdecoder.nim | 100 ++++++++++++++++++++++- compiler/icnif/nifencoder.nim | 44 ++++++++++ tests/icnif/tencode_node2node.nim | 8 ++ tests/icnif/testcode/modtestliterals.nim | 27 ++++++ 4 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 tests/icnif/testcode/modtestliterals.nim diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 051da61022545..8b887a09de8dc 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -22,6 +22,7 @@ proc getSysType(typeKind: TTypeKind): PType = result = sysTypes[typeKind] else: result = PType(itemId: ItemId(module: 0, item: typeKind.int32), kind: typeKind) + sysTypes[typeKind] = result type SplittedNifSym = object @@ -122,17 +123,106 @@ proc fromNifImport(c: var DecodeContext; n: var Cursor): PNode = result.add fromNifSymDef(c, n, nkImportStmt) inc n +proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = + inc n + case n.kind: + of StringLit: + let v = pool.strings[n.litId] + inc n + assert n.kind == StringLit + let suffix = pool.strings[n.litId] + let kind = case suffix + of "R": + nkRStrLit + of "T": + nkTripleStrLit + else: + assert false, "Unknown string literal suffix " & suffix + nkNone + result = newStrNode(kind, v) + of IntLit: + let v = pool.integers[n.intId] + inc n + assert n.kind == StringLit + let suffix = pool.strings[n.litId] + let kind = case suffix + of "i8": + tyInt8 + of "i16": + tyInt16 + of "i32": + tyInt32 + of "i64": + tyInt64 + else: + assert false, "Unknown int literal suffix " & suffix + tyNone + result = newIntTypeNode(v, getSysType(kind)) + of UIntLit: + let v = pool.uintegers[n.uintId] + inc n + assert n.kind == StringLit + let suffix = pool.strings[n.litId] + let kind = case suffix + of "u8": + tyUInt8 + of "u16": + tyUInt16 + of "u32": + tyUInt32 + of "u64": + tyUInt64 + else: + assert false, "Unknown uint literal suffix " & suffix + tyNone + result = newIntTypeNode(cast[BiggestInt](v), getSysType(kind)) + of FloatLit: + let v = pool.floats[n.floatId] + inc n + assert n.kind == StringLit + let suffix = pool.strings[n.litId] + let kind = case suffix + of "f32": + (nkFloat32Lit, tyFloat32) + of "f64": + (nkFloat64Lit, tyFloat64) + of "f128": + (nkFloat128Lit, tyFloat128) + else: + assert false, "Unknown uint literal suffix " & suffix + (nkNone, tyNone) + result = newFloatNode(kind[0], v) + result.typ() = getSysType(kind[1]) + else: + assert false, "invalid node in suf node " & $n.kind + inc n + assert n.kind == ParRi + inc n + proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = nil case n.kind: of DotToken: result = newNode(nkEmpty) inc n + of Symbol: + result = newSymNode(fromNifSymbol(c, n)) + of StringLit: + result = newStrNode(nkStrLit, pool.strings[n.litId]) + inc n + of CharLit: + result = newIntNode(nkCharLit, n.charLit.int) + inc n of IntLit: result = newIntTypeNode(pool.integers[n.intId], getSysType(tyInt)) inc n - of Symbol: - result = newSymNode(fromNifSymbol(c, n)) + of UIntLit: + result = newIntTypeNode(cast[BiggestInt](pool.uintegers[n.uintId]), getSysType(tyUInt)) + inc n + of FloatLit: + result = newFloatNode(nkFloatLit, pool.floats[n.floatId]) + result.typ() = getSysType(tyFloat) + inc n of ParLe: let kind = n.nodeKind case kind: @@ -146,6 +236,12 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = fromNifLocal(c, n, kind) of nkImportStmt: result = fromNifImport(c, n) + of nkNone: + case pool.tags[n.tagId]: + of "suf": + result = fromNifSuf(c, n) + else: + assert false, "Unknown tag " & pool.tags[n.tagId] else: assert false, "Not yet implemented " & $kind else: diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index ca19f0fee8139..48d2da35801cc 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -19,6 +19,16 @@ proc modname(c: var EncodeContext; idx: FileIndex): string = result = moduleSuffix(fp, cast[seq[string]](c.conf.searchPaths)) c.toSuffix[idx] = result +proc addIntLit(b: var Builder; i: int64; suffix: string) = + withTree(b, "suf"): + addIntLit(b, i) + addStrLit(b, suffix) + +proc addFloatLit(b: var Builder; f: float; suffix: string) = + withTree(b, "suf"): + addFloatLit(b, f) + addStrLit(b, suffix) + proc toNifSym(c: var EncodeContext; sym: PSym): string = result = sym.name.s & '.' & $sym.disamb let owner = sym.skipGenericOwner() @@ -74,8 +84,42 @@ proc toNif(c: var EncodeContext; n: PNode) = case n.kind: of nkEmpty: c.b.addEmpty() + of nkCharLit: + c.b.addCharLit n.intVal.char of nkIntLit: c.b.addIntLit n.intVal + of nkInt8Lit: + c.b.addIntLit n.intVal, "i8" + of nkInt16Lit: + c.b.addIntLit n.intVal, "i16" + of nkInt32Lit: + c.b.addIntLit n.intVal, "i32" + of nkInt64Lit: + c.b.addIntLit n.intVal, "i64" + of nkUIntLit: + c.b.addUIntLit cast[BiggestUInt](n.intVal) + of nkUInt8Lit: + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u8" + of nkUInt16Lit: + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u16" + of nkUInt32Lit: + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u32" + of nkUInt64Lit: + c.b.addUIntLit cast[BiggestUInt](n.intVal), "u64" + of nkFloatLit: + c.b.addFloatLit n.floatVal + of nkFloat32Lit: + c.b.addFloatLit n.floatVal, "f32" + of nkFloat64Lit: + c.b.addFloatLit n.floatVal, "f64" + of nkFloat128Lit: + c.b.addFloatLit n.floatVal, "f128" + of nkStrLit: + c.b.addStrLit n.strVal + of nkRStrLit: + c.b.addStrLit n.strVal, "R" + of nkTripleStrLit: + c.b.addStrLit n.strVal, "T" of nkIdentDefs: c.b.addTree toNifTag(n.kind) assert n.len == 3 diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 09cd9ec63407d..5a96eaaa0491f 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -2,12 +2,17 @@ import std/assertions import "../../compiler/icnif" / [nifencoder, nifdecoder] import "../../compiler" / [idents, ast, astalgo, options, pathutils, modulegraphs, modules, msgs, pipelines, syntaxes, sem, llstream, lineinfos] +# This test generates PNode by semchecks test code. +# Then it is used to test icnif/nifencoder and nifdecoder. + const TestCodeDir = currentSourcePath().AbsoluteFile.splitFile().dir / RelativeDir"testcode" proc newConfigRefForTest(): ConfigRef = var conf = newConfigRef() conf.setDefaultLibpath() conf.searchPaths.add(conf.libpath) + excl(conf.notes, hintProcessing) + excl(conf.mainPackageNotes, hintProcessing) result = conf proc newModuleGraphForSem(cache: IdentCache; conf: ConfigRef): ModuleGraph = @@ -105,9 +110,12 @@ proc testNifEncDec(graph: ModuleGraph; src: string) = let n2 = loadNifFromBuffer(nif, fullPath, graphForLoad) #debug(n) #debug(n2) + #if src == "modtestliterals.nim": + # echo nif assert eql(n, n2) var conf = newConfigRefForTest() var cache = newIdentCache() var graph = newModuleGraphForSem(cache, conf) testNifEncDec(graph, "modtest1.nim") +testNifEncDec(graph, "modtestliterals.nim") diff --git a/tests/icnif/testcode/modtestliterals.nim b/tests/icnif/testcode/modtestliterals.nim new file mode 100644 index 0000000000000..434b960678973 --- /dev/null +++ b/tests/icnif/testcode/modtestliterals.nim @@ -0,0 +1,27 @@ +var strlit = "test string" +var rstrlit = r"test\t raw" +var triplestrlit = """Triple +string +literal +""" +var charlit = 'a' +var intlit1 = 123456 +var intlit2 = -123456 +var int8litH = 127'i8 +var int8litL = -128'i8 +var int16litH = 32767'i16 +var int16litL = -32768'i16 +var int32litH = 2147483647'i32 +var int32litL = -2147483648'i32 +var int64litH = 9223372036854775807'i64 +var int64litL = -9223372036854775808'i64 + +var uintlitH = 18446744073709551615'u +var uint8litH = 255'u8 +var uint16litH = 65535'u16 +var uint32litH = 4294967295'u32 +var uint64litH = 18446744073709551615'u64 + +var floatlit = 1.25 +var float32lit = 1.25'f32 +var float64lit = 1.25'f64 From fa706383cb37b64c68a96a9055b1364aa11c4dd9 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sun, 12 Oct 2025 18:44:50 +0900 Subject: [PATCH 07/21] partially supports type sections --- compiler/icnif/nifdecoder.nim | 89 +++++-- compiler/icnif/nifdecodertypes.nim | 112 ++++++++ compiler/icnif/nifencoder.nim | 93 +++++-- compiler/icnif/nifencodertypes.nim | 262 +++++++++++++++++++ tests/icnif/tencode_node2node.nim | 61 ++++- tests/icnif/testcode/modtesttypesections.nim | 4 + 6 files changed, 572 insertions(+), 49 deletions(-) create mode 100644 compiler/icnif/nifdecodertypes.nim create mode 100644 compiler/icnif/nifencodertypes.nim create mode 100644 tests/icnif/testcode/modtesttypesections.nim diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 8b887a09de8dc..b0f092fe29002 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -8,21 +8,33 @@ type DecodeContext = object graph: ModuleGraph nifSymToPSym: Table[string, PSym] # foo.1.modsuffix -> PSym + types: Table[SymId, PType] + owner: PSym + sysTypes: Table[TTypeKind, PSym] + idgen: IdGenerator proc nodeKind(n: Cursor): TNodeKind {.inline.} = assert n.kind == ParLe pool.tags[n.tagId].parseNodeKind() -var sysTypes: Table[TTypeKind, PType] +const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} -proc getSysType(typeKind: TTypeKind): PType = - # This will be replaced with magicsys.getSysType - assert typeKind in {tyBool, tyChar, tyInt .. tyUInt64} - if typeKind in sysTypes: - result = sysTypes[typeKind] +proc getSysTypeSym(c: var DecodeContext; typeKind: TTypeKind): PSym = + assert typeKind in SysTypeKinds + if typeKind in c.sysTypes: + result = c.sysTypes[typeKind] else: - result = PType(itemId: ItemId(module: 0, item: typeKind.int32), kind: typeKind) - sysTypes[typeKind] = result + let ident = c.graph.cache.getIdent(toNifTag typeKind) + result = newSym(skType, ident, c.idgen, c.owner, unknownLineInfo) + var typ = newType(typeKind, c.idgen, nil) + typ.sym = result + result.typ = typ + c.sysTypes[typeKind] = result + +proc getSysType(c: var DecodeContext; typeKind: TTypeKind): PType = + # This will be replaced with magicsys.getSysType + assert typeKind in SysTypeKinds + getSysTypeSym(c, typeKind).typ type SplittedNifSym = object @@ -48,6 +60,9 @@ proc splitNifSym(s: string): SplittedNifSym = dec i proc fromNif(c: var DecodeContext; n: var Cursor): PNode +proc fromNifType(c: var DecodeContext; n: var Cursor): PType + +include nifdecodertypes proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = result = c.nifSymToPSym[pool.syms[n.symId]] @@ -56,6 +71,7 @@ proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = assert n.nodeKind == nkSym let symKind = case kind: + of nkTypeSection: skType of nkVarSection: skVar of nkLetSection: skLet of nkImportStmt: skModule @@ -109,13 +125,48 @@ proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) inc n result[0][0] = fromNifSymDef(c, n, kind) - result[0][1] = fromNif(c, n) + if n.kind == DotToken: + result[0][1] = newNode(nkEmpty) + inc n + else: + let typeSym = fromNifType(c, n).sym + assert typeSym != nil + result[0][1] = typeSym.newSymNode + result[0][0].sym.typ = typeSym.typ result[0][2] = fromNif(c, n) assert n.kind == ParRi # nkIdentDefs inc n assert n.kind == ParRi inc n +proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = + result = newNodeI(nkTypeDef, unknownLineInfo, 3) + inc n + let sym = fromNifSymDef(c, n, nkTypeSection) + if n.kind == DotToken: + result[0] = sym + else: + var postfix = newNodeI(nkPostfix, unknownLineInfo, 2) + postfix.add newIdentNode(c.graph.cache.getIdent("*"), unknownLineInfo) + postfix.add sym + result[0] = postfix + inc n + + # TODO: pragma + #result.add fromNif(c, n) + assert n.kind == DotToken + inc n + + # TODO: generics + result[1] = fromNif(c, n) + + # type body + result[2] = fromNifType(c, n).sym.newSymNode + sym.sym.typ = result[2].sym.typ + + assert n.kind == ParRi + inc n + proc fromNifImport(c: var DecodeContext; n: var Cursor): PNode = result = newNode(nkImportStmt) inc n @@ -157,7 +208,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = else: assert false, "Unknown int literal suffix " & suffix tyNone - result = newIntTypeNode(v, getSysType(kind)) + result = newIntTypeNode(v, c.getSysType(kind)) of UIntLit: let v = pool.uintegers[n.uintId] inc n @@ -175,7 +226,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = else: assert false, "Unknown uint literal suffix " & suffix tyNone - result = newIntTypeNode(cast[BiggestInt](v), getSysType(kind)) + result = newIntTypeNode(cast[BiggestInt](v), c.getSysType(kind)) of FloatLit: let v = pool.floats[n.floatId] inc n @@ -192,7 +243,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = assert false, "Unknown uint literal suffix " & suffix (nkNone, tyNone) result = newFloatNode(kind[0], v) - result.typ() = getSysType(kind[1]) + result.typ() = c.getSysType(kind[1]) else: assert false, "invalid node in suf node " & $n.kind inc n @@ -214,26 +265,28 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = newIntNode(nkCharLit, n.charLit.int) inc n of IntLit: - result = newIntTypeNode(pool.integers[n.intId], getSysType(tyInt)) + result = newIntTypeNode(pool.integers[n.intId], c.getSysType(tyInt)) inc n of UIntLit: - result = newIntTypeNode(cast[BiggestInt](pool.uintegers[n.uintId]), getSysType(tyUInt)) + result = newIntTypeNode(cast[BiggestInt](pool.uintegers[n.uintId]), c.getSysType(tyUInt)) inc n of FloatLit: result = newFloatNode(nkFloatLit, pool.floats[n.floatId]) - result.typ() = getSysType(tyFloat) + result.typ() = c.getSysType(tyFloat) inc n of ParLe: let kind = n.nodeKind case kind: - of nkStmtList: - result = newNode(nkStmtList) + of nkPostfix, nkTypeSection, nkStmtList: + result = newNode(kind) inc n while n.kind != ParRi: result.add fromNif(c, n) inc n of nkVarSection, nkLetSection: result = fromNifLocal(c, n, kind) + of nkTypeDef: + result = fromNifTypeSection(c, n) of nkImportStmt: result = fromNifImport(c, n) of nkNone: @@ -259,6 +312,8 @@ proc loadNif(stream: var Stream; modulePath: AbsoluteFile; graph: ModuleGraph): let modSuffix = moduleSuffix(modulePath.string, cast[seq[string]](graph.config.searchPaths)) let nifModSym = modSym.name.s & '.' & $modSym.disamb & '.' & modSuffix c.nifSymToPSym[nifModSym] = modSym + c.owner = modSym + c.idgen = idGeneratorFromModule(modSym) result = fromNif(c, n) diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim new file mode 100644 index 0000000000000..34b9560f73f7d --- /dev/null +++ b/compiler/icnif/nifdecodertypes.nim @@ -0,0 +1,112 @@ +# included from nifdecoder.nim + +proc expect(n: var Cursor; k: NifKind) = + if n.kind == k: + inc n + else: + when defined(debug): + writeStackTrace() + quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n + +proc readTypeKind(n: var Cursor; tag: string): TTypeKind = + if tag.len == 1: + case tag[0] + of 'i': + inc n + assert n.kind == IntLit + case pool.integers[n.intId] + of -1: result = tyInt + of 8: result = tyInt8 + of 16: result = tyInt16 + of 32: result = tyInt32 + of 64: result = tyInt64 + else: assert false + inc n + of 'u': + inc n + assert n.kind == IntLit + case pool.integers[n.intId] + of -1: result = tyUInt + of 8: result = tyUInt8 + of 16: result = tyUInt16 + of 32: result = tyUInt32 + of 64: result = tyUInt64 + else: assert false + inc n + of 'f': + inc n + assert n.kind == IntLit + case pool.integers[n.intId] + of -1: result = tyFloat + of 32: result = tyFloat32 + of 64: result = tyFloat64 + else: assert false + inc n + of 'c': + inc n + assert n.kind == IntLit + case pool.integers[n.intId] + of 8: result = tyChar + else: assert false + inc n + else: + result = parseTypeKind(tag) + inc n + else: + result = parseTypeKind(tag) + inc n + +proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: PType) = + case kind + of tyFromExpr, tyEnum: + res.n = fromNif(c, n) + of tyStatic: + res.addAllowNil fromNifType(c, n) + res.n = fromNif(c, n) + of tyObject: + # inheritance: + res.addAllowNil fromNifType(c, n) + res.n = fromNif(c, n) + else: + while n.kind != ParRi: + res.addAllowNil fromNifType(c, n) + expect n, ParRi + +proc fromNifType(c: var DecodeContext; n: var Cursor): PType = + case n.kind + of Symbol: + let s = n.symId + result = c.types.getOrDefault(s) + when true: + assert result != nil + else: + if result == nil: + let symA = c.syms.getOrDefault(s).sym + if symA != nil: + assert symA.kind == skType + result = symA.typ + else: + result = loadType(s, c) + c.types[s] = LoadedType(state: Loaded, typ: result) + of ParLe: + let tag = pool.tags[n.tag] + if tag == "missing": + result = nil + else: + let k = readTypeKind(n, tag) + if k in SysTypeKinds: + result = getSysType(c, k) + else: + #echo "Create non SysTypeKinds type: ", k, ": ", tag + result = newType(k, c.idgen, c.owner) + if n.kind == ParLe and pool.tags[n.tag] == "tf": + inc n + if n.kind == Ident: + result.flags = parseTypeFlags pool.strings[n.litId] + inc n + else: + expect n, Ident + expect n, ParRi + fromNifTypeImpl c, n, k, result + else: + expect n, ParLe diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 48d2da35801cc..263a7dbab792e 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -29,6 +29,9 @@ proc addFloatLit(b: var Builder; f: float; suffix: string) = addFloatLit(b, f) addStrLit(b, suffix) +proc toNif(c: var EncodeContext; n: PNode) +proc toNif(c: var EncodeContext; t: PType) + proc toNifSym(c: var EncodeContext; sym: PSym): string = result = sym.name.s & '.' & $sym.disamb let owner = sym.skipGenericOwner() @@ -42,7 +45,10 @@ proc toNifSym(c: var EncodeContext; sym: PSym): string = result.add modsuf proc symToNif(c: var EncodeContext; sym: PSym) = - c.b.addSymbol toNifSym(c, sym) + if sym.kind == skType and sym.typ != nil: + toNif c, sym.typ + else: + c.b.addSymbol toNifSym(c, sym) proc symdefToNif(c: var EncodeContext; n: PNode) = assert n.kind == nkSym @@ -71,6 +77,52 @@ proc symdefToNif(c: var EncodeContext; n: PNode) = c.b.addIntLit sym.position c.b.endTree() +include nifencodertypes + +proc toNifTypeSection(c: var EncodeContext; n: PNode) = + assert n.len == 3 + + var name: PNode + var visibility: PNode + var pragma: PNode + if n[0].kind == nkPragmaExpr: + pragma = n[0][1] + if n[0][0].kind == nkPostfix: + visibility = n[0][0][0] + name = n[0][0][1] + else: + name = n[0][0] + elif n[0].kind == nkPostfix: + visibility = n[0][0] + name = n[0][1] + else: + name = n[0] + + c.b.withTree(toNifTag(n.kind)): + symdefToNif(c, name) + + if visibility != nil: + c.b.addIdent "x" + else: + c.b.addEmpty + + # TODO: pragma + c.b.addEmpty + + # TODO: Generics + toNif c, n[1] + + let last = n[2] + if name.kind == nkSym: + if last.kind == nkEmpty and name.sym.typ != nil: + toNif c, name.sym.typ + elif name.sym.typ != nil and name.sym.typ.kind in {tyEnum, tyObject} and name.sym.typ.n != nil: + toNif c, name.sym.typ + else: + toNif c, last + else: + toNif c, last + proc toNifImport(c: var EncodeContext; n: PNode) = c.b.addTree toNifTag(n.kind) for i in 0 ..< n.len: @@ -84,6 +136,22 @@ proc toNif(c: var EncodeContext; n: PNode) = case n.kind: of nkEmpty: c.b.addEmpty() + of nkSym: + when false: + echo "nkSym: ", n.sym.name.s + if n.sym.kind == skModule: + echo "position = ", n.sym.position + debug(n.sym) + var o = n.sym.owner + for i in 0 .. 20: + if o == nil: + break + echo "owner ", i, ":" + if o.kind == skModule: + echo "position = ", o.position + debug(o) + o = o.owner + symToNif(c, n.sym) of nkCharLit: c.b.addCharLit n.intVal.char of nkIntLit: @@ -124,25 +192,14 @@ proc toNif(c: var EncodeContext; n: PNode) = c.b.addTree toNifTag(n.kind) assert n.len == 3 symdefToNif(c, n[0]) - toNif c, n[1] + if n[0].kind == nkSym: + toNif c, n[0].sym.typ + else: + toNif c, n[1] toNif c, n[2] c.b.endTree() - of nkSym: - when false: - echo "nkSym: ", n.sym.name.s - if n.sym.kind == skModule: - echo "position = ", n.sym.position - debug(n.sym) - var o = n.sym.owner - for i in 0 .. 20: - if o == nil: - break - echo "owner ", i, ":" - if o.kind == skModule: - echo "position = ", o.position - debug(o) - o = o.owner - symToNif(c, n.sym) + of nkTypeDef: + toNifTypeSection(c, n) of nkImportStmt: toNifImport(c, n) else: diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim new file mode 100644 index 0000000000000..339c4070749f2 --- /dev/null +++ b/compiler/icnif/nifencodertypes.nim @@ -0,0 +1,262 @@ +# included from nifencoder + +proc writeFlags[E](b: var Builder; flags: set[E]; tag: string) = + var flagsAsIdent = "" + genFlags(flags, flagsAsIdent) + if flagsAsIdent.len > 0: + b.withTree tag: + b.addIdent flagsAsIdent + +proc writeTypeFlags(c: var EncodeContext; t: PType) = + writeFlags c.b, t.flags, "tf" + +proc isNominalRef(t: PType): bool {.inline.} = + let e = t.elementType + t.sym != nil and e.kind == tyObject and (e.sym == nil or sfAnon in e.sym.flags) + +template singleElement(keyw: string) {.dirty.} = + c.b.withTree keyw: + writeTypeFlags(c, t) + if t.hasElementType: + toNif c, t.elementType + else: + c.b.addEmpty + +proc atom(c: var EncodeContext; t: PType; tag: string) = + c.b.withTree tag: + writeTypeFlags(c, t) + +proc atom(c: var EncodeContext; t: PType) = + c.b.withTree toNifTag(t.kind): + writeTypeFlags(c, t) + +template typeHead(c: var EncodeContext; t: PType; body: untyped) = + c.b.withTree toNifTag(t.kind): + writeTypeFlags(c, t) + body + +proc toNif(c: var EncodeContext; t: PType) = + if t == nil: + c.b.addKeyw "missing" + return + + case t.kind + of tyNone: atom c, t + of tyBool: atom c, t + of tyChar: atom c, t, "c +8" + of tyEmpty: c.b.addEmpty + of tyInt: atom c, t, "i -1" + of tyInt8: atom c, t, "i +8" + of tyInt16: atom c, t, "i +16" + of tyInt32: atom c, t, "i +32" + of tyInt64: atom c, t, "i +64" + of tyUInt: atom c, t, "u -1" + of tyUInt8: atom c, t, "u +8" + of tyUInt16: atom c, t, "u +16" + of tyUInt32: atom c, t, "u +32" + of tyUInt64: atom c, t, "u +64" + of tyFloat, tyFloat64: atom c, t, "f -1" + of tyFloat32: atom c, t, "f +32" + of tyFloat128: atom c, t, "f +128" + of tyAlias: + c.typeHead t: + toNif c, t.skipModifier + of tyNil: atom c, t + of tyUntyped: atom c, t + of tyTyped: atom c, t + of tyTypeDesc: + c.typeHead t: + if t.kidsLen == 0 or t.elementType.kind == tyNone: + c.b.addEmpty + else: + toNif c, t.elementType + of tyGenericParam: + # See the nim-sem spec: + c.typeHead t: + symToNif c, t.sym + #c.b.addIntLit t.sym.position + + of tyGenericInst: + c.typeHead t: + toNif c, t.genericHead + for _, a in t.genericInstParams: + toNif c, a + of tyGenericInvocation: + c.typeHead t: + toNif c, t.genericHead + for _, a in t.genericInvocationParams: + toNif c, a + of tyGenericBody: + #toNif c, t.last + c.typeHead t: + for _, son in t.ikids: toNif c, son + of tyDistinct, tyEnum: + if t.sym != nil: + symToNif c, t.sym + else: + c.typeHead t: + for _, son in t.ikids: toNif c, son + of tyPtr: + if isNominalRef(t): + symToNif c, t.sym + else: + c.typeHead t: + toNif c, t.elementType + of tyRef: + if isNominalRef(t): + symToNif c, t.sym + else: + c.typeHead t: + toNif c, t.elementType + of tyVar: + c.b.withTree(if isOutParam(t): "out" else: "mut"): + toNif c, t.elementType + of tyAnd: + c.typeHead t: + for _, son in t.ikids: toNif c, son + of tyOr: + c.typeHead t: + for _, son in t.ikids: toNif c, son + of tyNot: + c.typeHead t: toNif c, t.elementType + + of tyFromExpr: + if t.n == nil: + atom c, t, "err" + else: + c.typeHead t: + toNif c, t.n + + of tyArray: + c.typeHead t: + if t.hasElementType: + toNif c, t.elementType + toNif c, t.indexType + else: + c.b.addEmpty 2 + of tyUncheckedArray: + c.typeHead t: + if t.hasElementType: + toNif c, t.elementType + else: + c.b.addEmpty + + of tySequence: + singleElement toNifTag(t.kind) + + of tyOrdinal: + c.typeHead t: + if t.hasElementType: + toNif c, t.skipModifier + else: + c.b.addEmpty + + of tySet: singleElement toNifTag(t.kind) + of tyOpenArray: singleElement toNifTag(t.kind) + 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.. Date: Sun, 12 Oct 2025 19:28:33 +0900 Subject: [PATCH 08/21] clean up code --- compiler/icnif/nifdecoder.nim | 19 ------------------- compiler/icnif/nifdecodertypes.nim | 19 +++++++++++++++++++ compiler/icnif/nifencoder.nim | 4 ++-- compiler/icnif/nifencodertypes.nim | 4 ++-- tests/icnif/tencode_node2node.nim | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index b0f092fe29002..20bc9c198ad43 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -17,25 +17,6 @@ proc nodeKind(n: Cursor): TNodeKind {.inline.} = assert n.kind == ParLe pool.tags[n.tagId].parseNodeKind() -const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} - -proc getSysTypeSym(c: var DecodeContext; typeKind: TTypeKind): PSym = - assert typeKind in SysTypeKinds - if typeKind in c.sysTypes: - result = c.sysTypes[typeKind] - else: - let ident = c.graph.cache.getIdent(toNifTag typeKind) - result = newSym(skType, ident, c.idgen, c.owner, unknownLineInfo) - var typ = newType(typeKind, c.idgen, nil) - typ.sym = result - result.typ = typ - c.sysTypes[typeKind] = result - -proc getSysType(c: var DecodeContext; typeKind: TTypeKind): PType = - # This will be replaced with magicsys.getSysType - assert typeKind in SysTypeKinds - getSysTypeSym(c, typeKind).typ - type SplittedNifSym = object name: string diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index 34b9560f73f7d..a6d5c64f73f2f 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -8,6 +8,25 @@ proc expect(n: var Cursor; k: NifKind) = writeStackTrace() quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n +const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} + +proc getSysTypeSym(c: var DecodeContext; typeKind: TTypeKind): PSym = + assert typeKind in SysTypeKinds + if typeKind in c.sysTypes: + result = c.sysTypes[typeKind] + else: + let ident = c.graph.cache.getIdent(toNifTag typeKind) + result = newSym(skType, ident, c.idgen, c.owner, unknownLineInfo) + var typ = newType(typeKind, c.idgen, nil) + typ.sym = result + result.typ = typ + c.sysTypes[typeKind] = result + +proc getSysType(c: var DecodeContext; typeKind: TTypeKind): PType = + # This will be replaced with magicsys.getSysType + assert typeKind in SysTypeKinds + getSysTypeSym(c, typeKind).typ + proc readTypeKind(n: var Cursor; tag: string): TTypeKind = if tag.len == 1: case tag[0] diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 263a7dbab792e..8cbf71c94d757 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -83,8 +83,8 @@ proc toNifTypeSection(c: var EncodeContext; n: PNode) = assert n.len == 3 var name: PNode - var visibility: PNode - var pragma: PNode + var visibility: PNode = nil + var pragma: PNode = nil if n[0].kind == nkPragmaExpr: pragma = n[0][1] if n[0][0].kind == nkPostfix: diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 339c4070749f2..8013b7b5fbaa0 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -41,8 +41,8 @@ proc toNif(c: var EncodeContext; t: PType) = return case t.kind - of tyNone: atom c, t - of tyBool: atom c, t + of tyNone: atom c, t + of tyBool: atom c, t of tyChar: atom c, t, "c +8" of tyEmpty: c.b.addEmpty of tyInt: atom c, t, "i -1" diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 708e42b5f742e..bab74b98c5584 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -14,7 +14,7 @@ proc newConfigRefForTest(): ConfigRef = excl(conf.notes, hintProcessing) excl(conf.mainPackageNotes, hintProcessing) result = conf - + proc newModuleGraphForSem(cache: IdentCache; conf: ConfigRef): ModuleGraph = var graph = newModuleGraph(cache, conf) graph.setPipeLinePass(SemPass) From 95daba153b60d08ea54372eee3982ff5bf61bea9 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sun, 12 Oct 2025 19:51:18 +0900 Subject: [PATCH 09/21] uses SymId as key --- compiler/icnif/nifdecoder.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 20bc9c198ad43..1e04266d730bc 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -7,7 +7,7 @@ import enum2nif type DecodeContext = object graph: ModuleGraph - nifSymToPSym: Table[string, PSym] # foo.1.modsuffix -> PSym + nifSymToPSym: Table[SymId, PSym] types: Table[SymId, PType] owner: PSym sysTypes: Table[TTypeKind, PSym] @@ -46,7 +46,7 @@ proc fromNifType(c: var DecodeContext; n: var Cursor): PType include nifdecodertypes proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = - result = c.nifSymToPSym[pool.syms[n.symId]] + result = c.nifSymToPSym[n.symId] inc n proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = @@ -59,8 +59,8 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode else: skConst inc n assert n.kind == SymbolDef - let nifSym = pool.syms[n.symId] - let symdef = nifSym.splitNifSym + let nifSymId = n.symId + let symdef = pool.syms[nifSymId].splitNifSym assert symdef.name.len != 0 let ident = c.graph.cache.getIdent(symdef.name) inc n @@ -93,7 +93,7 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode disamb: symdef.id.int32) psym.setOwner(owner) result = newSymNode(psym) - let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSym, psym) + let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSymId, psym) assert not hasSym assert n.kind == ParRi @@ -292,7 +292,8 @@ proc loadNif(stream: var Stream; modulePath: AbsoluteFile; graph: ModuleGraph): let modSym = newModule(graph, fileInfoIdx(graph.config, modulePath)) let modSuffix = moduleSuffix(modulePath.string, cast[seq[string]](graph.config.searchPaths)) let nifModSym = modSym.name.s & '.' & $modSym.disamb & '.' & modSuffix - c.nifSymToPSym[nifModSym] = modSym + let nifModSymId = pool.syms.getOrIncl(nifModSym) + c.nifSymToPSym[nifModSymId] = modSym c.owner = modSym c.idgen = idGeneratorFromModule(modSym) From e5f32ff15b8d47cf66725d832513cdc1ed828d24 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Tue, 14 Oct 2025 08:20:06 +0900 Subject: [PATCH 10/21] makes using the type defined in type section in var section works --- compiler/icnif/nifdecoder.nim | 11 ++++------ compiler/icnif/nifdecodertypes.nim | 23 ++++++++++---------- compiler/icnif/nifencoder.nim | 9 ++++---- tests/icnif/tencode_node2node.nim | 15 ++++++++----- tests/icnif/testcode/modtesttypesections.nim | 2 +- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 1e04266d730bc..5529c6ad51775 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -106,14 +106,11 @@ proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) inc n result[0][0] = fromNifSymDef(c, n, kind) + result[0][1] = newNode(nkEmpty) if n.kind == DotToken: - result[0][1] = newNode(nkEmpty) inc n else: - let typeSym = fromNifType(c, n).sym - assert typeSym != nil - result[0][1] = typeSym.newSymNode - result[0][0].sym.typ = typeSym.typ + result[0][0].sym.typ = fromNifType(c, n) result[0][2] = fromNif(c, n) assert n.kind == ParRi # nkIdentDefs inc n @@ -142,8 +139,8 @@ proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = result[1] = fromNif(c, n) # type body - result[2] = fromNifType(c, n).sym.newSymNode - sym.sym.typ = result[2].sym.typ + result[2] = newNode(nkEmpty) + sym.sym.typ = fromNifType(c, n) assert n.kind == ParRi inc n diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index a6d5c64f73f2f..bb5d8a0cc2f50 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -96,17 +96,18 @@ proc fromNifType(c: var DecodeContext; n: var Cursor): PType = of Symbol: let s = n.symId result = c.types.getOrDefault(s) - when true: - assert result != nil - else: - if result == nil: - let symA = c.syms.getOrDefault(s).sym - if symA != nil: - assert symA.kind == skType - result = symA.typ - else: - result = loadType(s, c) - c.types[s] = LoadedType(state: Loaded, typ: result) + if result == nil: + let symA = c.nifSymToPSym.getOrDefault(s) + if symA != nil: + assert symA.kind == skType + result = symA.typ + assert symA != nil + #[ + else: + result = loadType(s, c) + c.types[s] = LoadedType(state: Loaded, typ: result) + ]# + inc n of ParLe: let tag = pool.tags[n.tag] if tag == "missing": diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 8cbf71c94d757..39451328cb4e2 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -45,7 +45,7 @@ proc toNifSym(c: var EncodeContext; sym: PSym): string = result.add modsuf proc symToNif(c: var EncodeContext; sym: PSym) = - if sym.kind == skType and sym.typ != nil: + if sfSystemModule in sym.owner.flags and sym.kind == skType and sym.typ != nil: toNif c, sym.typ else: c.b.addSymbol toNifSym(c, sym) @@ -192,10 +192,11 @@ proc toNif(c: var EncodeContext; n: PNode) = c.b.addTree toNifTag(n.kind) assert n.len == 3 symdefToNif(c, n[0]) - if n[0].kind == nkSym: - toNif c, n[0].sym.typ + if n[1].kind == nkSym: + symToNif c, n[1].sym else: - toNif c, n[1] + assert n[0].kind == nkSym + toNif c, n[0].sym.typ toNif c, n[2] c.b.endTree() of nkTypeDef: diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index bab74b98c5584..0a044e36defa4 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -59,6 +59,8 @@ proc sem(graph: ModuleGraph; path: AbsoluteFile): PNode = const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} # Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support +# Assumes `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder. +# So `eql(x, y) == eql(y, x)` is not always true. proc eql(x, y: PType): bool = if x == nil and y == nil: result = true @@ -116,12 +118,15 @@ proc eql(x, y: PNode): bool = of nkCharLit .. nkTripleStrLit: result = sameValue(x, y) of nkIdentDefs: - assert x.len == 3 + assert x.len == 3 and y.len == 3 if eql(x[0], y[0]) and eql(x[2], y[2]): - if x[1].kind == nkEmpty: - result = true - else: - result = eql(x[1], y[1]) + result = y[1].kind == nkEmpty and y[0].sym.typ != nil + else: + result = false + of nkTypeDef: + assert x.len == 3 and y.len == 3 + if eql(x[0], y[0]) and eql(x[1], y[1]): + result = y[2].kind == nkEmpty and y[0].sym.typ != nil else: result = false else: diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index e8c1a611606b7..00c2f01401714 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -1,4 +1,4 @@ type TestInt = int -#var x: TestInt +var x: TestInt From 055fc768a322a2151249248d32dec201d8be7dd9 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 15 Oct 2025 02:41:16 +0900 Subject: [PATCH 11/21] supports enum types --- compiler/icnif/nifdecoder.nim | 5 +++-- compiler/icnif/nifdecodertypes.nim | 9 ++++++++- compiler/icnif/nifencoder.nim | 6 +++--- compiler/icnif/nifencodertypes.nim | 11 ++++++----- tests/icnif/testcode/modtesttypesections.nim | 5 +++++ 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 5529c6ad51775..fffbdc5cc0bb2 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -43,8 +43,6 @@ proc splitNifSym(s: string): SplittedNifSym = proc fromNif(c: var DecodeContext; n: var Cursor): PNode proc fromNifType(c: var DecodeContext; n: var Cursor): PType -include nifdecodertypes - proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = result = c.nifSymToPSym[n.symId] inc n @@ -56,6 +54,7 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode of nkVarSection: skVar of nkLetSection: skLet of nkImportStmt: skModule + of nkEnumTy: skEnumField else: skConst inc n assert n.kind == SymbolDef @@ -99,6 +98,8 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode assert n.kind == ParRi inc n +include nifdecodertypes + proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result = newNodeI(kind, unknownLineInfo, 1) inc n diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index bb5d8a0cc2f50..5dd59b4eb13ec 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -77,7 +77,14 @@ proc readTypeKind(n: var Cursor; tag: string): TTypeKind = proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: PType) = case kind - of tyFromExpr, tyEnum: + of tyEnum: + res.n = newNode(nkEnumTy) + while n.kind != ParRi: + var sym = fromNifSymDef(c, n, nkEnumTy) + sym.sym.typ = res + res.n.add sym + expect n, ParRi + of tyFromExpr: res.n = fromNif(c, n) of tyStatic: res.addAllowNil fromNifType(c, n) diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 39451328cb4e2..9e05618b776f3 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -30,7 +30,7 @@ proc addFloatLit(b: var Builder; f: float; suffix: string) = addStrLit(b, suffix) proc toNif(c: var EncodeContext; n: PNode) -proc toNif(c: var EncodeContext; t: PType) +proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) proc toNifSym(c: var EncodeContext; sym: PSym): string = result = sym.name.s & '.' & $sym.disamb @@ -115,9 +115,9 @@ proc toNifTypeSection(c: var EncodeContext; n: PNode) = let last = n[2] if name.kind == nkSym: if last.kind == nkEmpty and name.sym.typ != nil: - toNif c, name.sym.typ + toNif c, name.sym.typ, true elif name.sym.typ != nil and name.sym.typ.kind in {tyEnum, tyObject} and name.sym.typ.n != nil: - toNif c, name.sym.typ + toNif c, name.sym.typ, true else: toNif c, last else: diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 8013b7b5fbaa0..41273ebf7c1e9 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -35,7 +35,7 @@ template typeHead(c: var EncodeContext; t: PType; body: untyped) = writeTypeFlags(c, t) body -proc toNif(c: var EncodeContext; t: PType) = +proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) = if t == nil: c.b.addKeyw "missing" return @@ -91,11 +91,12 @@ proc toNif(c: var EncodeContext; t: PType) = c.typeHead t: for _, son in t.ikids: toNif c, son of tyDistinct, tyEnum: - if t.sym != nil: - symToNif c, t.sym - else: + if isTypeSection: c.typeHead t: - for _, son in t.ikids: toNif c, son + for son in t.n: + symdefToNif c, son + else: + symToNif c, t.sym of tyPtr: if isNominalRef(t): symToNif c, t.sym diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index 00c2f01401714..e6a4aca0646d0 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -1,4 +1,9 @@ type TestInt = int + TestEnum = enum + X + Y var x: TestInt +var testEnum: TestEnum +var testEnum1 = X From f7e6f4b5e5276b14a1b340b9e621ac3b9869cb89 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 15 Oct 2025 04:13:45 +0900 Subject: [PATCH 12/21] fixes test code --- tests/icnif/tencode.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/icnif/tencode.nim b/tests/icnif/tencode.nim index 6f83e12d751c4..5c40c7e8faddc 100644 --- a/tests/icnif/tencode.nim +++ b/tests/icnif/tencode.nim @@ -15,9 +15,13 @@ block: (sym :testmod2.0.tesfd9rxn1 +1 . . "/tmp/testnim/testmod2.nim")) (var (identdefs - (sym :x.0.tesvp2f3v +2 testmod.0.tesvp2f3v ueg +0) . +123)) + (sym :x.0.tesvp2f3v +2 testmod.0.tesvp2f3v ueg +0) + (i -1 + (tf c3)) +123)) (var (identdefs - (sym :y.0.tesvp2f3v +3 testmod.0.tesvp2f3v g +0) . x.0.tesvp2f3v)))""" + (sym :y.0.tesvp2f3v +3 testmod.0.tesvp2f3v g +0) + (i -1 + (tf c3)) x.0.tesvp2f3v)))""" assert loadNifFromBuffer(TestNif, AbsoluteFile"/tmp/testnim/testmod.nim", graph).saveNifToBuffer(graph.config) == TestNif From b03464b53fbbc966436e677191c360b836ed3506 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 15 Oct 2025 11:48:35 +0900 Subject: [PATCH 13/21] supports distinct types --- compiler/icnif/nifdecodertypes.nim | 1 + compiler/icnif/nifencoder.nim | 4 +--- compiler/icnif/nifencodertypes.nim | 9 ++++++++- tests/icnif/testcode/modtesttypesections.nim | 2 ++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index 5dd59b4eb13ec..d9092b8ec7eb5 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -121,6 +121,7 @@ proc fromNifType(c: var DecodeContext; n: var Cursor): PType = result = nil else: let k = readTypeKind(n, tag) + assert k != tyNone if k in SysTypeKinds: result = getSysType(c, k) else: diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 9e05618b776f3..d800d4dd71659 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -114,9 +114,7 @@ proc toNifTypeSection(c: var EncodeContext; n: PNode) = let last = n[2] if name.kind == nkSym: - if last.kind == nkEmpty and name.sym.typ != nil: - toNif c, name.sym.typ, true - elif name.sym.typ != nil and name.sym.typ.kind in {tyEnum, tyObject} and name.sym.typ.n != nil: + if name.sym.typ != nil: toNif c, name.sym.typ, true else: toNif c, last diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 41273ebf7c1e9..7bb75c0bcde17 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -90,13 +90,20 @@ proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) = #toNif c, t.last c.typeHead t: for _, son in t.ikids: toNif c, son - of tyDistinct, tyEnum: + of tyEnum: if isTypeSection: c.typeHead t: for son in t.n: symdefToNif c, son else: symToNif c, t.sym + of tyDistinct: + if isTypeSection: + c.typeHead t: + for son in t.kids: + toNif c, son + else: + symToNif c, t.sym of tyPtr: if isNominalRef(t): symToNif c, t.sym diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index e6a4aca0646d0..48e9b50ae37f3 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -3,7 +3,9 @@ type TestEnum = enum X Y + TestDistinct = distinct int var x: TestInt var testEnum: TestEnum var testEnum1 = X +var testDistinct: TestDistinct From 588c48347ee9ddb528ebca8d7956b7d2e93ee47a Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 15 Oct 2025 23:46:44 +0900 Subject: [PATCH 14/21] encodes and decodes Node flags --- compiler/icnif/nifdecoder.nim | 11 ++++++++ compiler/icnif/nifencoder.nim | 42 ++++++++++++++++++++---------- compiler/icnif/nifencodertypes.nim | 7 ----- tests/icnif/tencode_node2node.nim | 2 +- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index fffbdc5cc0bb2..29d3e0b4b4b05 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -100,9 +100,19 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode include nifdecodertypes +proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = + result = {} + if n.kind == ParLe and pool.tags[n.tag] == "nf": + inc n + assert n.kind == Ident + result = parseNodeFlags(pool.strings[n.litId]) + inc n + expect n, ParRi + proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result = newNodeI(kind, unknownLineInfo, 1) inc n + result.flags = fromNifNodeFlags(n) assert n.nodeKind == nkIdentDefs result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) inc n @@ -259,6 +269,7 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = of nkPostfix, nkTypeSection, nkStmtList: result = newNode(kind) inc n + result.flags = fromNifNodeFlags(n) while n.kind != ParRi: result.add fromNif(c, n) inc n diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index d800d4dd71659..e50a2e69ba38f 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -29,6 +29,13 @@ proc addFloatLit(b: var Builder; f: float; suffix: string) = addFloatLit(b, f) addStrLit(b, suffix) +proc writeFlags[E](b: var Builder; flags: set[E]; tag: string) = + var flagsAsIdent = "" + genFlags(flags, flagsAsIdent) + if flagsAsIdent.len > 0: + b.withTree tag: + b.addIdent flagsAsIdent + proc toNif(c: var EncodeContext; n: PNode) proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) @@ -79,6 +86,15 @@ proc symdefToNif(c: var EncodeContext; n: PNode) = include nifencodertypes +proc writeNodeFlags(b: var Builder; flags: set[TNodeFlag]) {.inline.} = + writeFlags b, flags, "nf" + +template withNode(b: var Builder; n: PNode; body: untyped) = + addTree b, toNifTag(n.kind) + writeNodeFlags(b, n.flags) + body + endTree b + proc toNifTypeSection(c: var EncodeContext; n: PNode) = assert n.len == 3 @@ -187,26 +203,24 @@ proc toNif(c: var EncodeContext; n: PNode) = of nkTripleStrLit: c.b.addStrLit n.strVal, "T" of nkIdentDefs: - c.b.addTree toNifTag(n.kind) - assert n.len == 3 - symdefToNif(c, n[0]) - if n[1].kind == nkSym: - symToNif c, n[1].sym - else: - assert n[0].kind == nkSym - toNif c, n[0].sym.typ - toNif c, n[2] - c.b.endTree() + c.b.withNode n: + assert n.len == 3 + symdefToNif(c, n[0]) + if n[1].kind == nkSym: + symToNif c, n[1].sym + else: + assert n[0].kind == nkSym + toNif c, n[0].sym.typ + toNif c, n[2] of nkTypeDef: toNifTypeSection(c, n) of nkImportStmt: toNifImport(c, n) else: assert n.len > 0, $n.kind - c.b.addTree toNifTag(n.kind) - for i in 0 ..< n.len: - toNif c, n[i] - c.b.endTree() + c.b.withNode(n): + for i in 0 ..< n.len: + toNif c, n[i] proc saveNif(c: var EncodeContext; n: PNode) = c.b.addHeader "nim2", "nim2-ic-nif" diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 7bb75c0bcde17..bdf3da7930932 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -1,12 +1,5 @@ # included from nifencoder -proc writeFlags[E](b: var Builder; flags: set[E]; tag: string) = - var flagsAsIdent = "" - genFlags(flags, flagsAsIdent) - if flagsAsIdent.len > 0: - b.withTree tag: - b.addIdent flagsAsIdent - proc writeTypeFlags(c: var EncodeContext; t: PType) = writeFlags c.b, t.flags, "tf" diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 0a044e36defa4..22935de1961c2 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -105,7 +105,7 @@ proc eql(x, y: PNode): bool = result = true elif x == nil or y == nil: result = false - elif x.kind == y.kind and x.safeLen == y.safeLen: + elif x.kind == y.kind and x.safeLen == y.safeLen and x.flags == y.flags: case x.kind: of nkSym: result = eql(x.sym, y.sym) From 9b908d6d5a22f39141b055686e98eec97e23cf04 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Thu, 16 Oct 2025 01:40:13 +0900 Subject: [PATCH 15/21] adds incExpect and skipParRi proc --- compiler/icnif/nifdecoder.nim | 43 +++++++++++++++++++----------- compiler/icnif/nifdecodertypes.nim | 34 +++++++---------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 29d3e0b4b4b05..563cfc1f5d471 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -17,6 +17,26 @@ proc nodeKind(n: Cursor): TNodeKind {.inline.} = assert n.kind == ParLe pool.tags[n.tagId].parseNodeKind() +proc expect(n: Cursor; k: set[NifKind]) = + if n.kind notin k: + when defined(debug): + writeStackTrace() + quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n + +proc expect(n: Cursor; k: NifKind) {.inline.} = + expect n, {k} + +proc incExpect(n: var Cursor; k: set[NifKind]) = + inc n + expect n, k + +proc incExpect(n: var Cursor; k: NifKind) {.inline.} = + incExpect n, {k} + +proc skipParRi(n: var Cursor) = + expect n, {ParRi} + inc n + type SplittedNifSym = object name: string @@ -56,14 +76,12 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode of nkImportStmt: skModule of nkEnumTy: skEnumField else: skConst - inc n - assert n.kind == SymbolDef + incExpect n, SymbolDef let nifSymId = n.symId let symdef = pool.syms[nifSymId].splitNifSym assert symdef.name.len != 0 let ident = c.graph.cache.getIdent(symdef.name) - inc n - assert n.kind == IntLit + incExpect n, IntLit let itemId = pool.integers[n.intId].int32 inc n assert n.kind in {Symbol, DotToken}, $n.kind @@ -95,8 +113,7 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSymId, psym) assert not hasSym - assert n.kind == ParRi - inc n + skipParRi n include nifdecodertypes @@ -107,7 +124,7 @@ proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = assert n.kind == Ident result = parseNodeFlags(pool.strings[n.litId]) inc n - expect n, ParRi + skipParRi n proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result = newNodeI(kind, unknownLineInfo, 1) @@ -123,10 +140,8 @@ proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = else: result[0][0].sym.typ = fromNifType(c, n) result[0][2] = fromNif(c, n) - assert n.kind == ParRi # nkIdentDefs - inc n - assert n.kind == ParRi - inc n + skipParRi n # nkIdentDefs + skipParRi n proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = result = newNodeI(nkTypeDef, unknownLineInfo, 3) @@ -153,8 +168,7 @@ proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = result[2] = newNode(nkEmpty) sym.sym.typ = fromNifType(c, n) - assert n.kind == ParRi - inc n + skipParRi n proc fromNifImport(c: var DecodeContext; n: var Cursor): PNode = result = newNode(nkImportStmt) @@ -236,8 +250,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = else: assert false, "invalid node in suf node " & $n.kind inc n - assert n.kind == ParRi - inc n + skipParRi n proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = nil diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index d9092b8ec7eb5..185ceddb0e8c7 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -1,13 +1,5 @@ # included from nifdecoder.nim -proc expect(n: var Cursor; k: NifKind) = - if n.kind == k: - inc n - else: - when defined(debug): - writeStackTrace() - quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n - const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} proc getSysTypeSym(c: var DecodeContext; typeKind: TTypeKind): PSym = @@ -31,8 +23,7 @@ proc readTypeKind(n: var Cursor; tag: string): TTypeKind = if tag.len == 1: case tag[0] of 'i': - inc n - assert n.kind == IntLit + incExpect n, IntLit case pool.integers[n.intId] of -1: result = tyInt of 8: result = tyInt8 @@ -42,8 +33,7 @@ proc readTypeKind(n: var Cursor; tag: string): TTypeKind = else: assert false inc n of 'u': - inc n - assert n.kind == IntLit + incExpect n, IntLit case pool.integers[n.intId] of -1: result = tyUInt of 8: result = tyUInt8 @@ -53,8 +43,7 @@ proc readTypeKind(n: var Cursor; tag: string): TTypeKind = else: assert false inc n of 'f': - inc n - assert n.kind == IntLit + incExpect n, IntLit case pool.integers[n.intId] of -1: result = tyFloat of 32: result = tyFloat32 @@ -62,8 +51,7 @@ proc readTypeKind(n: var Cursor; tag: string): TTypeKind = else: assert false inc n of 'c': - inc n - assert n.kind == IntLit + incExpect n, IntLit case pool.integers[n.intId] of 8: result = tyChar else: assert false @@ -83,7 +71,7 @@ proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: var sym = fromNifSymDef(c, n, nkEnumTy) sym.sym.typ = res res.n.add sym - expect n, ParRi + inc n of tyFromExpr: res.n = fromNif(c, n) of tyStatic: @@ -96,7 +84,7 @@ proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: else: while n.kind != ParRi: res.addAllowNil fromNifType(c, n) - expect n, ParRi + inc n proc fromNifType(c: var DecodeContext; n: var Cursor): PType = case n.kind @@ -128,13 +116,11 @@ proc fromNifType(c: var DecodeContext; n: var Cursor): PType = #echo "Create non SysTypeKinds type: ", k, ": ", tag result = newType(k, c.idgen, c.owner) if n.kind == ParLe and pool.tags[n.tag] == "tf": + incExpect n, Ident + result.flags = parseTypeFlags pool.strings[n.litId] inc n - if n.kind == Ident: - result.flags = parseTypeFlags pool.strings[n.litId] - inc n - else: - expect n, Ident - expect n, ParRi + skipParRi n fromNifTypeImpl c, n, k, result else: expect n, ParLe + inc n From ac90f021dfa62c7814f0f425cd31a73110127906 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Thu, 16 Oct 2025 02:24:35 +0900 Subject: [PATCH 16/21] clean up code --- compiler/icnif/nifdecoder.nim | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 563cfc1f5d471..eb9e034ec15d7 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -83,22 +83,21 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode let ident = c.graph.cache.getIdent(symdef.name) incExpect n, IntLit let itemId = pool.integers[n.intId].int32 - inc n - assert n.kind in {Symbol, DotToken}, $n.kind + incExpect n, {Symbol, DotToken} let owner = if n.kind == Symbol: fromNifSymbol(c, n) else: inc n nil - assert n.kind in {Ident, DotToken}, $n.kind + expect n, {Ident, DotToken} let flags = if n.kind == Ident: pool.strings[n.litId].parseSymFlags else: {} inc n var position = if symKind == skModule: - assert n.kind == StringLit + expect n, StringLit let path = pool.strings[n.litId].AbsoluteFile fileInfoIdx(c.graph.config, path).int else: - assert n.kind == IntLit + expect n, IntLit pool.integers[n.intId] inc n @@ -120,8 +119,7 @@ include nifdecodertypes proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = result = {} if n.kind == ParLe and pool.tags[n.tag] == "nf": - inc n - assert n.kind == Ident + incExpect n, Ident result = parseNodeFlags(pool.strings[n.litId]) inc n skipParRi n @@ -182,8 +180,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = case n.kind: of StringLit: let v = pool.strings[n.litId] - inc n - assert n.kind == StringLit + incExpect n, StringLit let suffix = pool.strings[n.litId] let kind = case suffix of "R": @@ -196,8 +193,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = result = newStrNode(kind, v) of IntLit: let v = pool.integers[n.intId] - inc n - assert n.kind == StringLit + incExpect n, StringLit let suffix = pool.strings[n.litId] let kind = case suffix of "i8": @@ -214,8 +210,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = result = newIntTypeNode(v, c.getSysType(kind)) of UIntLit: let v = pool.uintegers[n.uintId] - inc n - assert n.kind == StringLit + incExpect n, StringLit let suffix = pool.strings[n.litId] let kind = case suffix of "u8": @@ -232,8 +227,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = result = newIntTypeNode(cast[BiggestInt](v), c.getSysType(kind)) of FloatLit: let v = pool.floats[n.floatId] - inc n - assert n.kind == StringLit + incExpect n, StringLit let suffix = pool.strings[n.litId] let kind = case suffix of "f32": From c16c667b7c2f191ae9630e556bc1e213e7ce1f66 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Fri, 17 Oct 2025 00:14:56 +0900 Subject: [PATCH 17/21] supports object types partially --- compiler/icnif/nifdecoder.nim | 1 + compiler/icnif/nifdecodertypes.nim | 19 +++++- compiler/icnif/nifencodertypes.nim | 14 +++- tests/icnif/tencode_node2node.nim | 68 ++++++++++++++++---- tests/icnif/testcode/modtesttypesections.nim | 5 ++ 5 files changed, 91 insertions(+), 16 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index eb9e034ec15d7..fc9dad180f118 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -75,6 +75,7 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode of nkLetSection: skLet of nkImportStmt: skModule of nkEnumTy: skEnumField + of nkRecList: skField else: skConst incExpect n, SymbolDef let nifSymId = n.symId diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index 185ceddb0e8c7..6f761a82cd2ea 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -12,6 +12,9 @@ proc getSysTypeSym(c: var DecodeContext; typeKind: TTypeKind): PSym = var typ = newType(typeKind, c.idgen, nil) typ.sym = result result.typ = typ + if typeKind == tyString: + var charSym = getSysTypeSym(c, tyChar) + result.typ.add charSym.typ c.sysTypes[typeKind] = result proc getSysType(c: var DecodeContext; typeKind: TTypeKind): PType = @@ -72,15 +75,25 @@ proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: sym.sym.typ = res res.n.add sym inc n + res.addAllowNil nil of tyFromExpr: res.n = fromNif(c, n) of tyStatic: res.addAllowNil fromNifType(c, n) res.n = fromNif(c, n) of tyObject: - # inheritance: - res.addAllowNil fromNifType(c, n) - res.n = fromNif(c, n) + # TODO: inheritance: + if n.kind == DotToken: + res.addAllowNil nil + inc n + else: + res.addAllowNil fromNifType(c, n) + res.n = newNode(nkRecList) + while n.kind != ParRi: + var sym = fromNifSymDef(c, n, nkRecList) + res.n.add sym + sym.sym.typ = fromNifType(c, n) + inc n else: while n.kind != ParRi: res.addAllowNil fromNifType(c, n) diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index bdf3da7930932..9a436fade71dd 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -225,7 +225,19 @@ proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) = of tyPointer: atom c, t of tyString: atom c, t of tyCstring: atom c, t - of tyObject: symToNif c, t.sym + of tyObject: + if isTypeSection: + c.typeHead t: + # TODO: inheritance: + c.b.addEmpty + for son in t.n: + symdefToNif c, son + if son.typ == nil: + c.b.addEmpty + else: + toNif c, son.typ + else: + symToNif c, t.sym of tyForward: atom c, t of tyError: atom c, t of tyBuiltInTypeClass: diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 22935de1961c2..0813031c65331 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -58,26 +58,61 @@ proc sem(graph: ModuleGraph; path: AbsoluteFile): PNode = const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64} +type + # Nim's AST has cycles that causes infinite recursive loop in eql procs. + # this is used to prevent that happen. + EqlContext = object + nodeStack: seq[PNode] + #symStack: seq[PSym] + typStack: seq[PType] + # Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support # Assumes `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder. # So `eql(x, y) == eql(y, x)` is not always true. -proc eql(x, y: PType): bool = +proc eql(x, y: PNode; c: var EqlContext): bool + +proc eql(x, y: PType; c: var EqlContext): bool = if x == nil and y == nil: result = true elif x == nil or y == nil: + echo "type is missing" result = false - elif x.kind == y.kind: - result = true - else: + elif x.kind != y.kind: echo "type kind mismatch: ", x.kind, "/", y.kind result = false + elif x.flags != y.flags: + echo "flag mismatch: ", x.flags, "/", y.flags + result = false + else: + if c.typStack.len != 0: + for i in countDown(c.typStack.len - 1, 0): + if x == c.typStack[i]: + # echo "cycle is detected in PType" + return true + c.typStack.add x + if not eql(x.n, y.n, c): + echo "type.n mismatch" + result = false + elif x.kidsLen != y.kidsLen: + echo "type kidsLen mismatch" + result = false + else: + result = true + for i in 0 ..< x.kidsLen: + if not eql(x[i], y[i], c): + echo "type kids mismatch: " + debug(x[i]) + debug(y[i]) + result = false + break + discard c.typStack.pop -proc eql(x, y: PSym): bool = +proc eql(x, y: PSym; c: var EqlContext): bool = if x == nil and y == nil: result = true elif x == nil or y == nil: result = false - elif x.kind == y.kind and eql(x.typ, y.typ) and x.name.s == y.name.s: + elif x.kind == y.kind and eql(x.typ, y.typ, c) and x.name.s == y.name.s: if (x.itemId.item == y.itemId.item and x.disamb == y.disamb and x.flags == y.flags) or (x.kind == skType and x.typ.kind in SysTypeKinds): if x.owner == nil and y.owner == nil: result = true @@ -100,15 +135,21 @@ proc eql(x, y: PSym): bool = else: result = false -proc eql(x, y: PNode): bool = +proc eql(x, y: PNode; c: var EqlContext): bool = if x == nil and y == nil: result = true elif x == nil or y == nil: result = false elif x.kind == y.kind and x.safeLen == y.safeLen and x.flags == y.flags: + if c.nodeStack.len != 0: + for i in countDown(c.nodeStack.len - 1, 0): + if x == c.nodeStack[i]: + # echo "cycle is detected in PNode" + return true + c.nodeStack.add x case x.kind: of nkSym: - result = eql(x.sym, y.sym) + result = eql(x.sym, y.sym, c) if not result: echo "Symbol mismatch:" debug(x.sym) @@ -119,22 +160,23 @@ proc eql(x, y: PNode): bool = result = sameValue(x, y) of nkIdentDefs: assert x.len == 3 and y.len == 3 - if eql(x[0], y[0]) and eql(x[2], y[2]): + if eql(x[0], y[0], c) and eql(x[2], y[2], c): result = y[1].kind == nkEmpty and y[0].sym.typ != nil else: result = false of nkTypeDef: assert x.len == 3 and y.len == 3 - if eql(x[0], y[0]) and eql(x[1], y[1]): + if eql(x[0], y[0], c) and eql(x[1], y[1], c): result = y[2].kind == nkEmpty and y[0].sym.typ != nil else: result = false else: result = true for i in 0 ..< x.safeLen: - if not eql(x[i], y[i]): + if not eql(x[i], y[i], c): result = false break + discard c.nodeStack.pop else: result = false @@ -143,13 +185,15 @@ proc testNifEncDec(graph: ModuleGraph; src: string) = let n = sem(graph, fullPath) let nif = saveNifToBuffer(n, graph.config) #debug(n) + #debug(n[0][0][0].typ) #echo nif # Don't reuse the ModuleGraph used for semcheck when load NIF. var graphForLoad = newModuleGraph(newIdentCache(), newConfigRefForTest()) let n2 = loadNifFromBuffer(nif, fullPath, graphForLoad) #debug(n2) - assert eql(n, n2) + var c = EqlContext() + assert eql(n, n2, c) var conf = newConfigRefForTest() var cache = newIdentCache() diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index 48e9b50ae37f3..dbc6d346a8b6b 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -5,7 +5,12 @@ type Y TestDistinct = distinct int + TestObject = object + x*: int + y: int + var x: TestInt var testEnum: TestEnum var testEnum1 = X var testDistinct: TestDistinct +var testObject: TestObject From 95ee8defedb3143750729d9c06d8160e73a6f23c Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Fri, 17 Oct 2025 06:05:38 +0900 Subject: [PATCH 18/21] fixes bug --- compiler/icnif/nifdecoder.nim | 4 ++-- tests/icnif/tencode_node2node.nim | 24 ++++++++++++++++---- tests/icnif/testcode/modtesttypesections.nim | 4 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index fc9dad180f118..3ef5dee04f81b 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -150,8 +150,8 @@ proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = result[0] = sym else: var postfix = newNodeI(nkPostfix, unknownLineInfo, 2) - postfix.add newIdentNode(c.graph.cache.getIdent("*"), unknownLineInfo) - postfix.add sym + postfix[0] = newIdentNode(c.graph.cache.getIdent("*"), unknownLineInfo) + postfix[1] = sym result[0] = postfix inc n diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index 0813031c65331..a7fc651e2bdd6 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -140,7 +140,13 @@ proc eql(x, y: PNode; c: var EqlContext): bool = result = true elif x == nil or y == nil: result = false - elif x.kind == y.kind and x.safeLen == y.safeLen and x.flags == y.flags: + elif x.kind != y.kind: + echo "node kind mismatch: ", x.kind, "/", y.kind + result = false + elif x.flags != y.flags: + echo "node flag mismatch: ", x.flags, "/", y.flags + result = false + elif x.safeLen == y.safeLen: if c.nodeStack.len != 0: for i in countDown(c.nodeStack.len - 1, 0): if x == c.nodeStack[i]: @@ -160,16 +166,23 @@ proc eql(x, y: PNode; c: var EqlContext): bool = result = sameValue(x, y) of nkIdentDefs: assert x.len == 3 and y.len == 3 - if eql(x[0], y[0], c) and eql(x[2], y[2], c): - result = y[1].kind == nkEmpty and y[0].sym.typ != nil + if eql(x[0], y[0], c) and eql(x[2], y[2], c) and y[1].kind == nkEmpty and y[0].sym.typ != nil: + result = true else: + echo "nkIdentDefs mismatch" result = false of nkTypeDef: assert x.len == 3 and y.len == 3 if eql(x[0], y[0], c) and eql(x[1], y[1], c): - result = y[2].kind == nkEmpty and y[0].sym.typ != nil + let sym = if y[0].kind == nkPostfix: + y[0][1].sym + else: + y[0].sym + result = y[2].kind == nkEmpty and sym.typ != nil else: result = false + if not result: + echo "nkTypeDef mismatch" else: result = true for i in 0 ..< x.safeLen: @@ -178,6 +191,9 @@ proc eql(x, y: PNode; c: var EqlContext): bool = break discard c.nodeStack.pop else: + echo "node length mismatch" + debug(x) + debug(y) result = false proc testNifEncDec(graph: ModuleGraph; src: string) = diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index dbc6d346a8b6b..2db0d1909ab20 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -9,8 +9,12 @@ type x*: int y: int + TestObject2* = object + x: TestObject + var x: TestInt var testEnum: TestEnum var testEnum1 = X var testDistinct: TestDistinct var testObject: TestObject +var testObject2*: TestObject2 From 6985b4fbbb1fb086107d5698d84f1c456020a838 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Fri, 17 Oct 2025 23:32:54 +0900 Subject: [PATCH 19/21] supports nil literal and ref/ptr types --- compiler/icnif/enum2nif.nim | 10 +++++----- compiler/icnif/nifdecoder.nim | 4 ++++ compiler/icnif/nifencoder.nim | 2 ++ compiler/icnif/nifencodertypes.nim | 16 +++------------- tests/icnif/testcode/modtestliterals.nim | 2 ++ tests/icnif/testcode/modtesttypesections.nim | 16 ++++++++++++++++ 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/compiler/icnif/enum2nif.nim b/compiler/icnif/enum2nif.nim index a4bbbf6e902d1..ecfdcfa0db2e6 100644 --- a/compiler/icnif/enum2nif.nim +++ b/compiler/icnif/enum2nif.nim @@ -1,4 +1,4 @@ -# Generated by enumgen.nim. DO NOT EDIT! +# Generated by gear2/generator/enumgen.nim in Nimony repo. DO NOT EDIT! import ".." / [ast, options] @@ -27,7 +27,7 @@ proc toNifTag*(s: TNodeKind): string = of nkStrLit: "strlit" of nkRStrLit: "rstrlit" of nkTripleStrLit: "triplestrlit" - of nkNilLit: "nillit" + of nkNilLit: "nil" of nkComesFrom: "comesfrom" of nkDotCall: "dotcall" of nkCommand: "cmd" @@ -197,7 +197,7 @@ proc parseNodeKind*(s: string): TNodeKind = of "strlit": nkStrLit of "rstrlit": nkRStrLit of "triplestrlit": nkTripleStrLit - of "nillit": nkNilLit + of "nil": nkNilLit of "comesfrom": nkComesFrom of "dotcall": nkDotCall of "cmd": nkCommand @@ -800,7 +800,7 @@ proc toNifTag*(s: TMagic): string = of mString: "string" of mCstring: "cstring" of mPointer: "pointer" - of mNil: "nil" + of mNil: "nilm" of mExpr: "exprm" of mStmt: "stmtm" of mTypeDesc: "typedesc" @@ -1082,7 +1082,7 @@ proc parseMagic*(s: string): TMagic = of "string": mString of "cstring": mCstring of "pointer": mPointer - of "nil": mNil + of "nilm": mNil of "exprm": mExpr of "stmtm": mStmt of "typedesc": mTypeDesc diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 3ef5dee04f81b..d08368786aae7 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -274,6 +274,10 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = of ParLe: let kind = n.nodeKind case kind: + of nkNilLit: + result = newNode(nkNilLit) + inc n + skipParRi n of nkPostfix, nkTypeSection, nkStmtList: result = newNode(kind) inc n diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index e50a2e69ba38f..98014adb0a9ce 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -202,6 +202,8 @@ proc toNif(c: var EncodeContext; n: PNode) = c.b.addStrLit n.strVal, "R" of nkTripleStrLit: c.b.addStrLit n.strVal, "T" + of nkNilLit: + c.b.addKeyw toNifTag(nkNilLit) of nkIdentDefs: c.b.withNode n: assert n.len == 3 diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 9a436fade71dd..16cc71825c649 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -3,10 +3,6 @@ proc writeTypeFlags(c: var EncodeContext; t: PType) = writeFlags c.b, t.flags, "tf" -proc isNominalRef(t: PType): bool {.inline.} = - let e = t.elementType - t.sym != nil and e.kind == tyObject and (e.sym == nil or sfAnon in e.sym.flags) - template singleElement(keyw: string) {.dirty.} = c.b.withTree keyw: writeTypeFlags(c, t) @@ -97,18 +93,12 @@ proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) = toNif c, son else: symToNif c, t.sym - of tyPtr: - if isNominalRef(t): - symToNif c, t.sym - else: - c.typeHead t: - toNif c, t.elementType - of tyRef: - if isNominalRef(t): + of tyRef, tyPtr: + if tfRefsAnonObj in t.flags and not isTypeSection: symToNif c, t.sym else: c.typeHead t: - toNif c, t.elementType + toNif c, t.elementType, isTypeSection of tyVar: c.b.withTree(if isOutParam(t): "out" else: "mut"): toNif c, t.elementType diff --git a/tests/icnif/testcode/modtestliterals.nim b/tests/icnif/testcode/modtestliterals.nim index 434b960678973..2d11cf8fa91fe 100644 --- a/tests/icnif/testcode/modtestliterals.nim +++ b/tests/icnif/testcode/modtestliterals.nim @@ -25,3 +25,5 @@ var uint64litH = 18446744073709551615'u64 var floatlit = 1.25 var float32lit = 1.25'f32 var float64lit = 1.25'f64 + +var nillit: ptr int = nil diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim index 2db0d1909ab20..7ff5b0e5be673 100644 --- a/tests/icnif/testcode/modtesttypesections.nim +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -12,9 +12,25 @@ type TestObject2* = object x: TestObject + TestRefInt = ref int + TestPtrInt = ptr int + + TestRefObj = ref object + x: int + + TestPtrObj = ptr object + x: int + var x: TestInt var testEnum: TestEnum var testEnum1 = X var testDistinct: TestDistinct var testObject: TestObject var testObject2*: TestObject2 + +var testRefInt: TestRefInt = nil +var testRefInt2: ref int = nil +var testPtrInt: TestPtrInt = nil +var testPtrInt2: ptr int = nil +var testRefObj: TestRefObj = nil +var testPtrObj: TestPtrObj = nil From edab1c243c7d3e47ec430cf5f9ff256a197b64c6 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sat, 18 Oct 2025 16:16:13 +0900 Subject: [PATCH 20/21] assigns PNode.typ --- compiler/icnif/nifdecoder.nim | 27 ++++++++-- compiler/icnif/nifdecodertypes.nim | 5 +- compiler/icnif/nifencodertypes.nim | 3 +- tests/icnif/tencode_node2node.nim | 86 ++++++++++++++++++------------ 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index d08368786aae7..062066411438c 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -125,6 +125,17 @@ proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = inc n skipParRi n +proc fromNifIntLit(c: var DecodeContext; n: var Cursor): PNode = + # See `getIntLitType` proc in semdata.nim + # Use intTypeCache? + let sysType = c.getSysType(tyInt) + var typ = copyType(sysType, c.idgen, sysType.owner) + let val = pool.integers[n.intId] + inc n + result = newIntTypeNode(val, typ) + typ.n = newIntTypeNode(val, typ) + typ.n.flags = {nfSem} + proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = result = newNodeI(kind, unknownLineInfo, 1) inc n @@ -137,7 +148,9 @@ proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = if n.kind == DotToken: inc n else: - result[0][0].sym.typ = fromNifType(c, n) + let typ = fromNifType(c, n) + result[0][0].sym.typ = typ + result[0][0].typ = typ result[0][2] = fromNif(c, n) skipParRi n # nkIdentDefs skipParRi n @@ -165,7 +178,9 @@ proc fromNifTypeSection(c: var DecodeContext; n: var Cursor): PNode = # type body result[2] = newNode(nkEmpty) - sym.sym.typ = fromNifType(c, n) + let typ = fromNifType(c, n) + sym.sym.typ = typ + sym.typ = typ skipParRi n @@ -192,6 +207,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = assert false, "Unknown string literal suffix " & suffix nkNone result = newStrNode(kind, v) + result.typ = c.getSysType(tyString) of IntLit: let v = pool.integers[n.intId] incExpect n, StringLit @@ -234,7 +250,7 @@ proc fromNifSuf(c: var DecodeContext; n: var Cursor): PNode = of "f32": (nkFloat32Lit, tyFloat32) of "f64": - (nkFloat64Lit, tyFloat64) + (nkFloat64Lit, tyFloat) of "f128": (nkFloat128Lit, tyFloat128) else: @@ -257,13 +273,14 @@ proc fromNif(c: var DecodeContext; n: var Cursor): PNode = result = newSymNode(fromNifSymbol(c, n)) of StringLit: result = newStrNode(nkStrLit, pool.strings[n.litId]) + result.typ = c.getSysType(tyString) inc n of CharLit: result = newIntNode(nkCharLit, n.charLit.int) + result.typ = c.getSysType(tyChar) inc n of IntLit: - result = newIntTypeNode(pool.integers[n.intId], c.getSysType(tyInt)) - inc n + result = fromNifIntLit(c, n) of UIntLit: result = newIntTypeNode(cast[BiggestInt](pool.uintegers[n.uintId]), c.getSysType(tyUInt)) inc n diff --git a/compiler/icnif/nifdecodertypes.nim b/compiler/icnif/nifdecodertypes.nim index 6f761a82cd2ea..606551c602302 100644 --- a/compiler/icnif/nifdecodertypes.nim +++ b/compiler/icnif/nifdecodertypes.nim @@ -73,6 +73,7 @@ proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: while n.kind != ParRi: var sym = fromNifSymDef(c, n, nkEnumTy) sym.sym.typ = res + sym.typ = res res.n.add sym inc n res.addAllowNil nil @@ -92,7 +93,9 @@ proc fromNifTypeImpl(c: var DecodeContext; n: var Cursor; kind: TTypeKind; res: while n.kind != ParRi: var sym = fromNifSymDef(c, n, nkRecList) res.n.add sym - sym.sym.typ = fromNifType(c, n) + let typ = fromNifType(c, n) + sym.sym.typ = typ + sym.typ = typ inc n else: while n.kind != ParRi: diff --git a/compiler/icnif/nifencodertypes.nim b/compiler/icnif/nifencodertypes.nim index 16cc71825c649..a649dcdc7d23c 100644 --- a/compiler/icnif/nifencodertypes.nim +++ b/compiler/icnif/nifencodertypes.nim @@ -44,8 +44,9 @@ proc toNif(c: var EncodeContext; t: PType; isTypeSection = false) = of tyUInt16: atom c, t, "u +16" of tyUInt32: atom c, t, "u +32" of tyUInt64: atom c, t, "u +64" - of tyFloat, tyFloat64: atom c, t, "f -1" + of tyFloat: atom c, t, "f -1" of tyFloat32: atom c, t, "f +32" + of tyFloat64: atom c, t, "f +64" of tyFloat128: atom c, t, "f +128" of tyAlias: c.typeHead t: diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index a7fc651e2bdd6..e20dc74bb1da8 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -65,6 +65,7 @@ type nodeStack: seq[PNode] #symStack: seq[PSym] typStack: seq[PType] + conf: ConfigRef # used to print the line info when there is a mismatch. # Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support # Assumes `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder. @@ -92,6 +93,8 @@ proc eql(x, y: PType; c: var EqlContext): bool = c.typStack.add x if not eql(x.n, y.n, c): echo "type.n mismatch" + debug(x.n) + debug(y.n) result = false elif x.kidsLen != y.kidsLen: echo "type kidsLen mismatch" @@ -145,6 +148,8 @@ proc eql(x, y: PNode; c: var EqlContext): bool = result = false elif x.flags != y.flags: echo "node flag mismatch: ", x.flags, "/", y.flags + debug(x) + debug(y) result = false elif x.safeLen == y.safeLen: if c.nodeStack.len != 0: @@ -153,43 +158,53 @@ proc eql(x, y: PNode; c: var EqlContext): bool = # echo "cycle is detected in PNode" return true c.nodeStack.add x - case x.kind: - of nkSym: - result = eql(x.sym, y.sym, c) - if not result: - echo "Symbol mismatch:" - debug(x.sym) - debug(y.sym) - debug(x.sym.typ) - debug(y.sym.typ) - of nkCharLit .. nkTripleStrLit: - result = sameValue(x, y) - of nkIdentDefs: - assert x.len == 3 and y.len == 3 - if eql(x[0], y[0], c) and eql(x[2], y[2], c) and y[1].kind == nkEmpty and y[0].sym.typ != nil: - result = true - else: - echo "nkIdentDefs mismatch" - result = false - of nkTypeDef: - assert x.len == 3 and y.len == 3 - if eql(x[0], y[0], c) and eql(x[1], y[1], c): - let sym = if y[0].kind == nkPostfix: - y[0][1].sym - else: - y[0].sym - result = y[2].kind == nkEmpty and sym.typ != nil - else: - result = false - if not result: - echo "nkTypeDef mismatch" + if x.kind != nkNilLit and not eql(x.typ, y.typ, c): + # ignore node type if it is nil literal. + # current nifencoder doesn't encode the type of nil lit. + echo "PNode type mismatch at ", `$`(c.conf, x.info), ":" + debug(x) + debug(y) + debug(x.typ) + debug(y.typ) + result = false else: - result = true - for i in 0 ..< x.safeLen: - if not eql(x[i], y[i], c): + case x.kind: + of nkSym: + result = eql(x.sym, y.sym, c) + if not result: + echo "Symbol mismatch:" + debug(x.sym) + debug(y.sym) + debug(x.sym.typ) + debug(y.sym.typ) + of nkCharLit .. nkTripleStrLit: + result = sameValue(x, y) + of nkIdentDefs: + assert x.len == 3 and y.len == 3 + if eql(x[0], y[0], c) and eql(x[2], y[2], c) and y[1].kind == nkEmpty and y[0].sym.typ != nil: + result = true + else: + echo "nkIdentDefs mismatch" result = false - break - discard c.nodeStack.pop + of nkTypeDef: + assert x.len == 3 and y.len == 3 + if eql(x[0], y[0], c) and eql(x[1], y[1], c): + let sym = if y[0].kind == nkPostfix: + y[0][1].sym + else: + y[0].sym + result = y[2].kind == nkEmpty and sym.typ != nil + else: + result = false + if not result: + echo "nkTypeDef mismatch" + else: + result = true + for i in 0 ..< x.safeLen: + if not eql(x[i], y[i], c): + result = false + break + discard c.nodeStack.pop else: echo "node length mismatch" debug(x) @@ -209,6 +224,7 @@ proc testNifEncDec(graph: ModuleGraph; src: string) = let n2 = loadNifFromBuffer(nif, fullPath, graphForLoad) #debug(n2) var c = EqlContext() + c.conf = graph.config assert eql(n, n2, c) var conf = newConfigRefForTest() From c14448b6887c94d8b8628ee2f822d22e105829f6 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sun, 19 Oct 2025 13:49:54 +0900 Subject: [PATCH 21/21] supports importc pragma with variables --- compiler/icnif/nifdecoder.nim | 36 ++++++++++++++-- compiler/icnif/nifencoder.nim | 7 ++- tests/icnif/tencode_node2node.nim | 57 +++++++++++++++++++++---- tests/icnif/testcode/modtestpragmas.nim | 3 ++ 4 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 tests/icnif/testcode/modtestpragmas.nim diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim index 062066411438c..d83120719279e 100644 --- a/compiler/icnif/nifdecoder.nim +++ b/compiler/icnif/nifdecoder.nim @@ -100,14 +100,21 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode else: expect n, IntLit pool.integers[n.intId] + incExpect n, ParLe + var loc = TLoc() + loc.k = pool.tags[n.tagId].parseLocKind() + incExpect n, StringLit + loc.snippet.add pool.strings[n.litId] inc n + skipParRi n var psym = PSym(itemId: ItemId(module: 0, item: itemId), kind: symKind, name: ident, flags: flags, position: position, - disamb: symdef.id.int32) + disamb: symdef.id.int32, + loc: loc) psym.setOwner(owner) result = newSymNode(psym) let hasSym = c.nifSymToPSym.hasKeyOrPut(nifSymId, psym) @@ -115,6 +122,18 @@ proc fromNifSymDef(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode skipParRi n +proc createPragmaNode(c: var DecodeContext; sym: PSym): PNode = + var pragmas = newNode(nkPragma) + if sfImportc in sym.flags: + let ident = newNode(nkIdent) + ident.ident = c.graph.cache.getIdent("importc") + pragmas.add ident + + if pragmas.len == 0: + result = nil + else: + result = pragmas + include nifdecodertypes proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = @@ -143,14 +162,23 @@ proc fromNifLocal(c: var DecodeContext; n: var Cursor; kind: TNodeKind): PNode = assert n.nodeKind == nkIdentDefs result[0] = newNodeI(nkIdentDefs, unknownLineInfo, 3) inc n - result[0][0] = fromNifSymDef(c, n, kind) + var symNode = fromNifSymDef(c, n, kind) + let pragmas = createPragmaNode(c, symNode.sym) + if pragmas == nil: + result[0][0] = symNode + else: + var pragmaExpr = newNode(nkPragmaExpr) + pragmaExpr.add symNode + pragmaExpr.add pragmas + result[0][0] = pragmaExpr + result[0][1] = newNode(nkEmpty) if n.kind == DotToken: inc n else: let typ = fromNifType(c, n) - result[0][0].sym.typ = typ - result[0][0].typ = typ + symNode.sym.typ = typ + symNode.typ = typ result[0][2] = fromNif(c, n) skipParRi n # nkIdentDefs skipParRi n diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim index 98014adb0a9ce..36ed94f46fe6a 100644 --- a/compiler/icnif/nifencoder.nim +++ b/compiler/icnif/nifencoder.nim @@ -82,6 +82,8 @@ proc symdefToNif(c: var EncodeContext; n: PNode) = c.b.addStrLit path else: c.b.addIntLit sym.position + c.b.withTree toNifTag(sym.loc.k): + c.b.addStrLit sym.loc.snippet c.b.endTree() include nifencodertypes @@ -207,7 +209,10 @@ proc toNif(c: var EncodeContext; n: PNode) = of nkIdentDefs: c.b.withNode n: assert n.len == 3 - symdefToNif(c, n[0]) + if n[0].kind == nkPragmaExpr: + symdefToNif(c, n[0][0]) + else: + symdefToNif(c, n[0]) if n[1].kind == nkSym: symToNif c, n[1].sym else: diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim index e20dc74bb1da8..9d106b817a922 100644 --- a/tests/icnif/tencode_node2node.nim +++ b/tests/icnif/tencode_node2node.nim @@ -63,7 +63,7 @@ type # this is used to prevent that happen. EqlContext = object nodeStack: seq[PNode] - #symStack: seq[PSym] + symStack: seq[PSym] typStack: seq[PType] conf: ConfigRef # used to print the line info when there is a mismatch. @@ -72,6 +72,16 @@ type # So `eql(x, y) == eql(y, x)` is not always true. proc eql(x, y: PNode; c: var EqlContext): bool +proc eql(x, y: TLoc): bool = + if x.k != y.k: + echo "loc kind mismatch: ", x.k, "/", y.k + result = false + elif x.snippet != y.snippet: + echo "loc snippet mismatch: ", x.snippet, "/", y.snippet + result = false + else: + result = true + proc eql(x, y: PType; c: var EqlContext): bool = if x == nil and y == nil: result = true @@ -114,9 +124,37 @@ proc eql(x, y: PSym; c: var EqlContext): bool = if x == nil and y == nil: result = true elif x == nil or y == nil: + echo "symbol is missing" + result = false + elif x.kind != y.kind: + echo "symbol kind mismatch: ", x.kind, "/", y.kind + result = false + elif x.name.s != y.name.s: + echo "symbol name mismatch: ", x.name.s, "/", y.name.s + result = false + elif x.flags != y.flags: + echo "symbol flag mismatch: ", x.flags, "/", y.flags + result = false + elif not eql(x.loc, y.loc): + echo "symbol.loc mismatch" + result = false + elif not (x.kind == skType and x.typ.kind in SysTypeKinds) and + not (x.itemId.item == y.itemId.item and x.disamb == y.disamb and x.flags == y.flags): + echo "symbol itemId or disamb mismatch" result = false - elif x.kind == y.kind and eql(x.typ, y.typ, c) and x.name.s == y.name.s: - if (x.itemId.item == y.itemId.item and x.disamb == y.disamb and x.flags == y.flags) or (x.kind == skType and x.typ.kind in SysTypeKinds): + elif (x.flags * {sfImportc, sfExportc} != {}) and (x.loc.snippet != y.loc.snippet): + echo "importc or exportc mismatch: ", x.loc.snippet, "/", y.loc.snippet + result = false + else: + if c.symStack.len != 0: + for i in countDown(c.symStack.len - 1, 0): + if x == c.symStack[i]: + return true + c.symStack.add x + if not eql(x.typ, y.typ, c): + echo "symbol type mismatch: " + result = false + else: if x.owner == nil and y.owner == nil: result = true elif x.owner == nil or y.owner == nil: @@ -133,10 +171,7 @@ proc eql(x, y: PSym; c: var EqlContext): bool = debug(x.owner) debug(y.owner) result = false - else: - result = false - else: - result = false + discard c.symStack.pop proc eql(x, y: PNode; c: var EqlContext): bool = if x == nil and y == nil: @@ -181,7 +216,10 @@ proc eql(x, y: PNode; c: var EqlContext): bool = result = sameValue(x, y) of nkIdentDefs: assert x.len == 3 and y.len == 3 - if eql(x[0], y[0], c) and eql(x[2], y[2], c) and y[1].kind == nkEmpty and y[0].sym.typ != nil: + if eql(x[0], y[0], c) and + eql(x[2], y[2], c) and + y[1].kind == nkEmpty and + (if y[0].kind == nkPragmaExpr: y[0][0] else: y[0]).sym.typ != nil: result = true else: echo "nkIdentDefs mismatch" @@ -214,8 +252,8 @@ proc eql(x, y: PNode; c: var EqlContext): bool = proc testNifEncDec(graph: ModuleGraph; src: string) = let fullPath = TestCodeDir / RelativeFile(src) let n = sem(graph, fullPath) - let nif = saveNifToBuffer(n, graph.config) #debug(n) + let nif = saveNifToBuffer(n, graph.config) #debug(n[0][0][0].typ) #echo nif @@ -233,3 +271,4 @@ var graph = newModuleGraphForSem(cache, conf) testNifEncDec(graph, "modtest1.nim") testNifEncDec(graph, "modtestliterals.nim") testNifEncDec(graph, "modtesttypesections.nim") +testNifEncDec(graph, "modtestpragmas.nim") diff --git a/tests/icnif/testcode/modtestpragmas.nim b/tests/icnif/testcode/modtestpragmas.nim new file mode 100644 index 0000000000000..7b8e22ccdfe0a --- /dev/null +++ b/tests/icnif/testcode/modtestpragmas.nim @@ -0,0 +1,3 @@ +#var exportcTest {.exportc.}: int +var importcTest {.importc.}: int +#var y* {.importc, header: "test.h".}: int