private static string MangleDefaultConstructorName(ES_TypeInfo *typeName, bool isStatic) { // Sample name: "struct.System.Numerics__Vector2" using var mangleChars = new StructPooledList <char> (CL_ClearMode.Auto); // The prefix. if (!isStatic) { mangleChars.AddRange("defaultConstructor!"); } else { mangleChars.AddRange("defaultStaticConstructor!"); } // The namespace. var namespaceName = typeName->Name.NamespaceName.Span; ES_Encodings.Identifier.GetChars(namespaceName, mangleChars.AddSpan(namespaceName.Length)); // The mangled namespace separator. mangleChars.Add('_', 2); // The function name. var structName = typeName->Name.TypeName.Span; ES_Encodings.Identifier.GetChars(structName, mangleChars.AddSpan(structName.Length)); return(mangleChars.Span.GetPooledString()); }
private void CreateFunctions_Function( ref TranslationUnitData transUnit, ES_NamespaceData.Builder namespaceBuilder, SymbolStack <FrontendSymbol> symbols, SourceData unitSrc, ES_TypeInfo *parentType, ES_AstFunctionDefinition funcDef ) { Debug.Assert(Environment is not null); Debug.Assert(EnvironmentBuilder is not null); var sourceUnit = transUnit.Name; var idPool = Environment.IdPool; // Get the namespace and function names. var funcName = Environment.IdPool.GetIdentifier(funcDef.Name.Text.Span); // Get the fully-qualified name. ES_FullyQualifiedName fullyQualifiedName; if (parentType == null) { var namespaceName = namespaceBuilder.NamespaceData.NamespaceName; fullyQualifiedName = new ES_FullyQualifiedName(namespaceName, funcName); } else { using var namespaceBytes = UnmanagedArray <byte> .GetArray(parentType->Name.NamespaceName.Length + 2 + parentType->Name.TypeName.Length); var span = namespaceBytes.Span; parentType->Name.NamespaceName.Span.CopyTo(span); span = span [parentType->Name.NamespaceName.Length..];
public ES_ArrayTypeData(ES_FullyQualifiedName fullyQualifiedName, [NotNull] ES_TypeInfo *elemType, int dims) { TypeInfo = new (ES_TypeTag.Array, ES_AccessModifier.Public, ES_TypeFlag.None, ArrayPointer <byte> .Null, fullyQualifiedName); TypeInfo.RuntimeSize = sizeof(void *) + sizeof(int); elementType = elemType; dimCount = dims; }
private bool TypeSizing_AnalyzeCycles_Traverse([NotNull] ES_TypeInfo *innerType, [NotNull] ES_TypeInfo *containingType) { switch (innerType->TypeTag) { case ES_TypeTag.Struct: case ES_TypeTag.Class: break; case ES_TypeTag.Const: case ES_TypeTag.Immutable: { var constData = (ES_ConstData *)innerType; return(TypeSizing_AnalyzeCycles_Traverse(constData->InnerType, containingType)); } case ES_TypeTag.Array: case ES_TypeTag.Void: case ES_TypeTag.Bool: case ES_TypeTag.Int: case ES_TypeTag.Float: case ES_TypeTag.Function: case ES_TypeTag.Enum: case ES_TypeTag.Interface: case ES_TypeTag.Reference: return(false); default: throw new NotImplementedException("Type not implemented yet."); } foreach (var memberAddr in innerType->MembersList.MembersList.Span) { var member = memberAddr.Address; if (member->MemberType != ES_MemberType.Field) { continue; } if (member->Flags.HasFlag(ES_MemberFlags.Static)) { continue; } var field = (ES_MemberData_Variable *)member; if (field->Type == containingType) { return(true); } if (TypeSizing_AnalyzeCycles_Traverse(field->Type, containingType)) { return(true); } } return(false); }
public ES_MemberData_Variable( ArrayPointer <byte> name, ArrayPointer <byte> srcUnit, ES_AccessModifier accessMod, ES_MemberFlags flags, int offset, ES_TypeInfo *type ) { Info = new ES_MemberData(accessMod, ES_MemberType.Field, flags, name, srcUnit); Offset = offset; Type = type; }
private unsafe void AddTypeToTree(ES_TypeInfo *typeData, TreeViewItem parentItem) { string typeType = null; typeType = typeData->TypeTag switch { ES_TypeTag.Void => "Void", ES_TypeTag.Bool => "Bool", ES_TypeTag.Int => "Int", ES_TypeTag.Float => "Float", ES_TypeTag.Enum => "Enum", ES_TypeTag.Struct => "Struct", ES_TypeTag.Class => "Class", ES_TypeTag.Interface => "Interface", ES_TypeTag.Function => "Prototype", ES_TypeTag.Reference => "Reference", ES_TypeTag.Array => "Array", ES_TypeTag.Const => "Const", ES_TypeTag.Immutable => "Immutable", _ => "[UNRECOGNIZED]", }; var typeNode = AddNodeToTree($"{typeType} {typeData->Name.TypeNameString}", parentItem); AddNodeToTree($"Runtime size: {typeData->RuntimeSize}", typeNode); AddNodeToTree($"Fully qualified name: {typeData->Name.GetNameAsTypeString ()}", typeNode); AddNodeToTree($"Source unit: {typeData->SourceUnitString}", typeNode); if (typeData->TypeTag == ES_TypeTag.Function) { var funcData = (ES_FunctionPrototypeData *)typeData; AddNodeToTree($"Return type: {funcData->ReturnType->Name.GetNameAsTypeString ()}", typeNode); var argsListNode = AddNodeToTree($"Arguments list", typeNode); foreach (var arg in funcData->ArgumentsList.Span) { var argType = arg.ArgType.ToString(); string argTypeName; if (arg.ValueType != null) { argTypeName = arg.ValueType->Name.GetNameAsTypeString(); } else { argTypeName = "[NULL]"; } AddNodeToTree($"{argType} {argTypeName}", argsListNode); } } }
public static T *AllocObject <T> (ES_TypeInfo *type, bool pinned, T defaultVal = default) where T : unmanaged { EnsureInitialized(); var ptr = (T *)garbageCollector !.AllocateObject(type, pinned); *ptr = defaultVal; return(ptr); }
public static ExpressionData NewType(ES_AstExpression expr, ES_TypeInfo *typeInfo) { return(new ExpressionData { Expr = expr, TypeInfo = typeInfo, Type = null, Function = null }); }
public ES_ConstData( ES_FullyQualifiedName fullyQualifiedName, ES_TypeInfo *innerType, bool immutable ) { var tag = immutable ? ES_TypeTag.Immutable : ES_TypeTag.Const; TypeInfo = new ES_TypeInfo(tag, ES_AccessModifier.Public, ES_TypeFlag.None, ArrayPointer <byte> .Null, fullyQualifiedName); InnerType = innerType; }
public ES_FunctionPrototypeData(ES_AccessModifier accessMod, ES_TypeInfo *retType, ArrayPointer <ES_FunctionPrototypeArgData> argsList, ES_FullyQualifiedName fullyQualifiedName, ArrayPointer <byte> sourceUnit ) { TypeInfo = new (ES_TypeTag.Function, accessMod, ES_TypeFlag.NoNew, sourceUnit, fullyQualifiedName); TypeInfo.RuntimeSize = IntPtr.Size; returnType = retType; argumentsList = argsList; }
private static bool FoldConstants_EnsureCompat(ES_TypeInfo *dstType, ref ES_AstExpression expr) { if (dstType is null) { return(false); } switch (expr) { case ES_AstFloat32ConstantExpression exprFlt64: { if (dstType->TypeTag != ES_TypeTag.Float) { return(false); } var dstTypeFlt = (ES_FloatTypeData *)dstType; if (dstTypeFlt->FloatSize < ES_FloatSize.Single) { return(false); } switch (dstTypeFlt->FloatSize) { case ES_FloatSize.Single: return(true); case ES_FloatSize.Double: expr = new ES_AstFloat64ConstantExpression(exprFlt64.Value, expr); return(true); default: throw new NotImplementedException("Size not implemented."); } } case ES_AstFloat64ConstantExpression exprFlt64: { if (dstType->TypeTag != ES_TypeTag.Float) { return(false); } var dstTypeFlt = (ES_FloatTypeData *)dstType; if (dstTypeFlt->FloatSize < ES_FloatSize.Double) { return(false); } return(dstTypeFlt->FloatSize switch { ES_FloatSize.Double => true, _ => throw new NotImplementedException("Size not implemented."), }); }
private static ExpressionSyntax CompileCode_NewObject(ES_TypeInfo *type, ExpressionSyntax?assignValue) { var isReference = type->TypeTag == ES_TypeTag.Reference; // Get the roslyn type. var intPtrType = IdentifierName(nameof(IntPtr)); var roslynType = GetRoslynType(type); // Generate the member access. var accessExpr = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(ES_GarbageCollector)), GenericName(Identifier(nameof(ES_GarbageCollector.AllocObject))).WithTypeArgumentList( TypeArgumentList(SingletonSeparatedList(!isReference ? roslynType : intPtrType)) ) ); // Construct the args list. using var argsList = new StructPooledList <SyntaxNodeOrToken> (CL_ClearMode.Auto); argsList.EnsureCapacity(3); // Generate the pointer type syntax for the type pointer. var pointerTypeSyntax = PointerType(IdentifierName(nameof(ES_TypeInfo))); // Add the type pointer. argsList.Add(Argument(PointerLiteral(type, pointerTypeSyntax))); // Add the "pinned" bool. argsList.Add(Token(SyntaxKind.CommaToken)); argsList.Add(Argument(BoolLiteral(false))); // Add the value to assign. if (assignValue is not null) { argsList.Add(Token(SyntaxKind.CommaToken)); if (isReference) { assignValue = CastExpression(intPtrType, assignValue); } argsList.Add(Argument(assignValue)); } // Generate the function call. ExpressionSyntax ret = InvocationExpression(accessExpr) .WithArgumentList(ArgumentList(SeparatedListSpan <ArgumentSyntax> (argsList.Span))); if (isReference) { ret = CastExpression(PointerType(roslynType), ret); } return(ret); }
public ES_ReferenceData( ES_FullyQualifiedName fullyQualifiedName, ES_TypeInfo *pointedType ) { TypeInfo = new (ES_TypeTag.Reference, ES_AccessModifier.Public, ES_TypeFlag.None, ArrayPointer <byte> .Null, fullyQualifiedName) { RuntimeSize = sizeof(void *) }; PointedType = pointedType; } #endregion }
private static ES_TypeInfo *StripFirstConst(ES_TypeInfo *type) { switch (type->TypeTag) { case ES_TypeTag.Const: case ES_TypeTag.Immutable: { var constData = (ES_ConstData *)type; return(constData->InnerType); } default: return(type); } }
internal static string MangleMemberFunctionName([DisallowNull] ES_TypeInfo *owner, [DisallowNull] ES_FunctionData *func) { using var mangleChars = new StructPooledList <char> (CL_ClearMode.Auto); // The type name. mangleChars.AddRange(owner->Name.TypeNameString); // The mangled namespace separator. mangleChars.AddRange("__"); // The function name. mangleChars.AddRange(func->Name.TypeNameString); return(mangleChars.Span.GetPooledString()); }
private static TypeSyntax GetRoslynType(ES_TypeInfo *type) { switch (type->TypeTag) { case ES_TypeTag.Void: return(PredefinedType(Token(SyntaxKind.VoidKeyword))); case ES_TypeTag.Bool: return(PredefinedType(Token(SyntaxKind.BoolKeyword))); case ES_TypeTag.Int: { var intType = (ES_IntTypeData *)type; return(GetIntType(intType->IntSize, intType->Unsigned)); } case ES_TypeTag.Float: { var floatType = (ES_FloatTypeData *)type; return(GetFloatType(floatType->FloatSize)); } case ES_TypeTag.Struct: return(IdentifierName(MangleTypeName(type))); case ES_TypeTag.Reference: { var pointerType = (ES_ReferenceData *)type; var pointedType = GetRoslynType(pointerType->PointedType); return(PointerType(pointedType)); } case ES_TypeTag.Array: return(PointerType(IdentifierName(MangleTypeName(type)))); case ES_TypeTag.Function: case ES_TypeTag.Class: case ES_TypeTag.Enum: case ES_TypeTag.Interface: case ES_TypeTag.Const: case ES_TypeTag.Immutable: { var constData = (ES_ConstData *)type; return(GetRoslynType(constData->InnerType)); } default: throw new NotImplementedException("Type not implemented."); } }
internal static bool UnaryOpCompat( EchelonScriptEnvironment env, ES_TypeInfo *exprType, SimpleUnaryExprType op, out ES_TypeInfo *finalType, out bool isConst ) { finalType = env.TypeUnknownValue; isConst = false; return(exprType->TypeTag switch { ES_TypeTag.Int => UnaryOpCompat_Int(env, exprType, op, out finalType, out isConst), ES_TypeTag.Bool => UnaryOpCompat_Bool(env, exprType, op, out finalType, out isConst), ES_TypeTag.Float => UnaryOpCompat_Float(env, exprType, op, out finalType, out isConst), ES_TypeTag.Reference => UnaryOpCompat_Ref(env, exprType, op, out finalType, out isConst), _ => false, });
private unsafe string GetTypeName(ES_TypeInfo *type) { switch (type->TypeTag) { case ES_TypeTag.UNKNOWN: return("[UNKNOWN]"); case ES_TypeTag.Null: return("[null]"); case ES_TypeTag.Reference: { var refData = (ES_ReferenceData *)type; return($"{GetTypeName (refData->PointedType)}&"); } case ES_TypeTag.Array: { var arrData = (ES_ArrayTypeData *)type; var dimCount = arrData->DimensionsCount; var dimString = dimCount > 1 ? new string (',', arrData->DimensionsCount - 1) : string.Empty; return($"{GetTypeName (arrData->ElementType)} [{dimString}]"); } /*case ES_TypeTag.Const: * case ES_TypeTag.Immutable: * return "Const/Immutable [NOT IMPLEMENTED INTERNALLY]";*/ case ES_TypeTag.Void: case ES_TypeTag.Bool: case ES_TypeTag.Int: case ES_TypeTag.Float: return(type->Name.TypeNameString); //case ES_TypeTag.Function: return "Function [NOT IMPLEMENTED]"; case ES_TypeTag.Struct: case ES_TypeTag.Class: case ES_TypeTag.Interface: case ES_TypeTag.Enum: return(type->Name.GetNameAsTypeString()); default: return($"{type->TypeTag} [NOT IMPLEMENTED]"); } }
public static bool BinaryOpCompat( EchelonScriptEnvironment env, ES_TypeInfo *lhsType, ES_TypeInfo *rhsType, SimpleBinaryExprType exprType, out ES_TypeInfo *finalType, out bool isConst ) { finalType = env.TypeUnknownValue; if (lhsType->TypeTag == ES_TypeTag.UNKNOWN || rhsType->TypeTag == ES_TypeTag.UNKNOWN) { isConst = false; return(true); } if (lhsType->TypeTag == ES_TypeTag.Null || rhsType->TypeTag == ES_TypeTag.Null) { return(BinaryOpCompat_Null(env, lhsType, rhsType, exprType, out finalType, out isConst)); } return((lhsType->TypeTag, rhsType->TypeTag) switch { (ES_TypeTag.Int, ES_TypeTag.Int) => BinaryOpCompat_IntInt(env, lhsType, rhsType, exprType, out finalType, out isConst), (ES_TypeTag.Bool, ES_TypeTag.Bool) => BinaryOpCompat_BoolBool(env, lhsType, rhsType, exprType, out finalType, out isConst), (ES_TypeTag.Float, ES_TypeTag.Float) => BinaryOpCompat_FloatFloat(env, lhsType, rhsType, exprType, out finalType, out isConst), (ES_TypeTag.Float, ES_TypeTag.Int) => BinaryOpCompat_FloatInt(env, lhsType, rhsType, exprType, out finalType, out isConst), (ES_TypeTag.Reference, ES_TypeTag.Reference) => BinaryOpCompat_RefRef(env, lhsType, rhsType, exprType, out finalType, out isConst), (ES_TypeTag.Array, ES_TypeTag.Array) => BinaryOpCompat_ArrayArray(env, lhsType, rhsType, exprType, out finalType, out isConst), _ => isConst = false, });
private void CreateTypes_Aggregate( ref TranslationUnitData transUnit, ES_NamespaceData.Builder namespaceBuilder, ES_TypeTag type, ES_AstAggregateDefinition typeDef ) { var namespaceName = namespaceBuilder.NamespaceData.NamespaceName; var typeName = Environment !.IdPool.GetIdentifier(typeDef.Name.Text.Span); if (namespaceBuilder.CheckTypeExists(typeName, null) != null) { errorList.Add(ES_FrontendErrors.GenTypeAlreadyDefined( namespaceBuilder.NamespaceData.NamespaceNameString, typeDef.Name.Text.Span.GetPooledString(), typeDef.Name )); return; } ES_TypeInfo *typeData = null; if (type == ES_TypeTag.Class) { var classBuilder = namespaceBuilder.GetOrCreateClass(typeDef.AccessModifier, typeName, transUnit.Name); typeData = &classBuilder.ClassData->TypeInfo; } else if (type == ES_TypeTag.Struct) { var structBuilder = namespaceBuilder.GetOrCreateStruct(typeDef.AccessModifier, typeName, transUnit.Name); typeData = &structBuilder.StructData->TypeInfo; } else { Debug.Fail("Not implemented/supported."); } EnvironmentBuilder !.PointerAstMap.Add((IntPtr)typeData, typeDef); }
private static ExpressionSyntax CompileCode_NullCheck(ExpressionSyntax ptrExpr, ES_TypeInfo *pointedType) { var isRef = pointedType->IsReferenceType(); if (isRef) { ptrExpr = CastExpression( PointerType(PredefinedType(Token(SyntaxKind.ByteKeyword))), ptrExpr ); } var value = CompileCode_NullCheck(ptrExpr); if (isRef) { value = CastExpression( PointerType(GetRoslynType(pointedType)), ptrExpr ); } return(value); }
private static ES_IntTypeData *DetermineIntLiteralType( ref PassData passData, ES_AstIntegerLiteralExpression intLitExpr, ES_TypeInfo *expectedType, bool negated ) { ES_IntTypeData *expectedIntType = null; bool?unsigned = null; var isSigned = intLitExpr.Signed; var chosenSize = intLitExpr.Size; if (expectedType != null && expectedType->TypeTag == ES_TypeTag.Int) { expectedIntType = (ES_IntTypeData *)expectedType; if (isSigned == null) { isSigned = !expectedIntType->Unsigned; } } ES_IntSize size; ES_IntSize minSize; var tooBig = false; var value = intLitExpr.Value; if (isSigned == false || intLitExpr.HexBin) { if (value <= byte.MaxValue) { minSize = ES_IntSize.Int8; } else if (value <= ushort.MaxValue) { minSize = ES_IntSize.Int16; } else if (value <= uint.MaxValue) { minSize = ES_IntSize.Int32; } else { minSize = ES_IntSize.Int64; } } else if (!negated) { if (value <= (ulong)sbyte.MaxValue) { minSize = ES_IntSize.Int8; } else if (value <= (ulong)short.MaxValue) { minSize = ES_IntSize.Int16; } else if (value <= int.MaxValue) { minSize = ES_IntSize.Int32; } else if (value <= long.MaxValue) { minSize = ES_IntSize.Int64; } else { minSize = ES_IntSize.Int64; unsigned = true; if (isSigned == true) { tooBig = true; } } } else { unsigned = false; if (value <= ((ulong)sbyte.MaxValue) + 1) { minSize = ES_IntSize.Int8; } else if (value <= ((ulong)short.MaxValue) + 1) { minSize = ES_IntSize.Int16; } else if (value <= ((ulong)int.MaxValue) + 1) { minSize = ES_IntSize.Int32; } else if (value <= ((ulong)long.MaxValue) + 1) { minSize = ES_IntSize.Int64; } else { minSize = ES_IntSize.Int64; unsigned = true; if (isSigned == true) { tooBig = true; } } } tooBig |= ( (chosenSize is not null && chosenSize.Value < minSize) || (unsigned == true && isSigned == true) ); if (tooBig) { var errSize = minSize; if (chosenSize is not null) { errSize = chosenSize.Value; } passData.ErrorList.Add(ES_FrontendErrors.GenIntLitTooBig(isSigned !.Value, errSize, intLitExpr.Token)); if (unsigned is null && isSigned == false) { unsigned = true; } } else { if (chosenSize is not null) { minSize = chosenSize.Value; } if (unsigned is null && isSigned is not null) { unsigned = !isSigned.Value; } } size = minSize; if (expectedIntType is not null) { var isCompat = false; var expectsUnsign = expectedIntType->Unsigned; var expectedSize = expectedIntType->IntSize; if (intLitExpr.HexBin && (isSigned is null || isSigned == !expectsUnsign) && minSize <= expectedSize) { isCompat = true; } else if (unsigned == expectsUnsign && minSize <= expectedSize) { isCompat = true; } if (isCompat) { size = expectedSize; unsigned = expectsUnsign; } }
public static FrontendSymbol NewType(ES_TypeInfo *type) => new (FrontendSymbolType.Type, type, 0);
public static FrontendSymbol NewVariable(ES_TypeInfo *type, FrontendSymbolFlags flags = 0) => new (FrontendSymbolType.Variable, type, flags);
public static void *AllocObject(ES_TypeInfo *type, bool pinned) { EnsureInitialized(); return(garbageCollector !.AllocateObject(type, pinned)); }
public ES_FunctionPrototypeArgData(ES_ArgumentType argType, ES_TypeInfo *valueType) { ArgType = argType; ValueType = valueType; }
public static ESIR_Struct Struct(ES_TypeInfo *type, ESIR_List <ESIR_MemberNode> members) => Struct(ValueNode(type), members);
private static void FoldConstants_ExplicitCast_ToFloat(ES_TypeInfo *dstType, in ES_AstExpression innerExpr, ref ES_AstExpression expr, out bool isRedundant)
private void TypeSizing_SizeType([NotNull] ES_TypeInfo *type, ArrayPointer <nint> refListRefType) { Debug.Assert(Environment is not null); Debug.Assert(EnvironmentBuilder is not null); if (type->Flags.HasFlag(ES_TypeFlag.Analyzed)) { return; } var hasRefs = !type->Flags.HasFlag(ES_TypeFlag.NoRefs); switch (type->TypeTag) { case ES_TypeTag.Array: case ES_TypeTag.Interface: case ES_TypeTag.Reference: { type->RuntimeSize = sizeof(void *); type->RefsList = refListRefType; type->Flags &= ~ES_TypeFlag.NoRefs; type->Flags |= ES_TypeFlag.Analyzed; return; } case ES_TypeTag.Void: case ES_TypeTag.Bool: case ES_TypeTag.Int: case ES_TypeTag.Float: case ES_TypeTag.Function: case ES_TypeTag.Enum: type->Flags |= ES_TypeFlag.Analyzed; return; case ES_TypeTag.Const: case ES_TypeTag.Immutable: { var constData = (ES_ConstData *)type; TypeSizing_SizeType(constData->InnerType, refListRefType); type->RuntimeSize = constData->InnerType->RuntimeSize; type->RefsList = constData->InnerType->RefsList; type->Flags = constData->InnerType->Flags | ES_TypeFlag.Analyzed; return; } case ES_TypeTag.Struct: case ES_TypeTag.Class: break; default: throw new NotImplementedException("Type not implemented yet."); } using var refsList = new StructPooledList <nint> (CL_ClearMode.Auto); var curOffs = 0; foreach (var memberAddr in type->MembersList.MembersList.Span) { var member = memberAddr.Address; if (member->MemberType != ES_MemberType.Field) { continue; } if (member->Flags.HasFlag(ES_MemberFlags.Static)) { continue; } var field = (ES_MemberData_Variable *)member; field->Offset = curOffs; TypeSizing_SizeType(field->Type, refListRefType); curOffs += field->Type->RuntimeSize; foreach (var refOffs in field->Type->RefsList.Span) { refsList.Add(field->Offset + refOffs); } hasRefs |= !field->Type->Flags.HasFlag(ES_TypeFlag.NoRefs); } type->RuntimeSize = curOffs; type->RefsList = ArrayPointer <nint> .Null; if (refsList.Count > 0) { type->RefsList = EnvironmentBuilder.MemoryManager.GetArrayAligned <nint> (refsList.Count, sizeof(nint)); refsList.Span.CopyTo(type->RefsList.Span); } type->Flags &= ~ES_TypeFlag.NoRefs; if (!hasRefs) { type->Flags |= ES_TypeFlag.NoRefs; } type->Flags |= ES_TypeFlag.Analyzed; }
public unsafe static ESIR_TypeNode TypeNode (ES_TypeInfo* ptr) { Debug.Assert (ptr is not null); return TypeNode (ValueNode (ptr)); }