private void DeserializeTypes(Json.Expression types, ref TypeDef[] typeDefs) { // // TODO: confirm this behavior, technically "optional" in Bonsai spec, so value could be null. // if (types is not Json.ArrayExpression typeTable) { throw new BonsaiParseException("Expected a JSON array containing the type table.", types); } var n = typeTable.ElementCount; typeDefs = new TypeDef[n]; for (var i = 0; i < n; i++) { var type = typeTable.GetElement(i); var typeDef = TypeDef.FromJson(this, type); typeDefs[i] = typeDef; } }
/// <summary> /// Gets a type space object from a JSON representation. /// </summary> /// <param name="expression">JSON representation of the type space.</param> /// <param name="typeResolutionService">Type resolution service. Can be null.</param> /// <returns>Type space for the given JSON representation.</returns> public static TypeSpace FromJson(Json.Expression expression, ITypeResolutionService typeResolutionService) { // // Referencing mscorlib for default lookups. See SimpleTypeDef.FromJson for the // special treatment of this assembly in order to shorten names in serialization // payload. // if (typeResolutionService != null) { typeResolutionService.ReferenceAssembly(typeof(int).Assembly.GetName() /* mscorlib */); } // // Inverse of ToJson. // var defs = ((Json.ArrayExpression)expression).Elements; // // First, get enough type reference objects to support the full range of ordinals. // var typeRefs = Enumerable.Range(0, defs.Count).Select(i => new TypeRef(i)).ToArray(); // // Using a findRef delegate, we can now import the type definitions. Notice this // assumes that type references are in a fixed zero-based range. // var findRef = new Func <Json.Expression, TypeRef>(r => typeRefs[TypeRef.FromJson(r).Ordinal]); var typeDefs = defs.Select(def => TypeDef.FromJson(def, findRef, typeResolutionService)).ToArray(); // // Next, we associate all of the type references with their corresponding definition, // again based on ordinal number indexes. // var j = 0; foreach (var typeDef in typeDefs) { var typeRef = typeRefs[j++]; typeRef.Definition = typeDef; } // // The first phase of defining the type space consists of compilation of the types, // resulting in recreation of structural types. Entries are added to the type def // table to allow for Lookup calls during deserialization of the expression tree. // var res = new TypeSpace(); var structuralTypes = new List <StructuralTypeDef>(); foreach (var typeRef in typeRefs) { var def = typeRef.Definition; res._typeDefs[typeRef] = def; def.Compile(res._compiler, typeResolutionService); // // Structural types need a separate compilation stage in order to "freeze" the // reconstructed types. See comment below for more information. // if (def is StructuralTypeDef std) { structuralTypes.Add(std); } } // // Second stage of compilation, triggering the CreateType on TypeBuilder to cause // final construction of the types. // foreach (var structuralType in structuralTypes) { structuralType.ToType(); // side-effect described above } // // The following piece of code can be re-enabled for debugging purposes in order to // see a Type-based index for type references. This is only needed for serialization, // so we eliminate this step for deserialization. // /* * foreach (var typeRef in typeRefs) * { * var type = typeRef.Definition.ToType(); * res._typeRefs[type] = typeRef; * } */ return(res); }