private void CompileClass(Parser parser, ByteBuffer buffer, ClassDefinition classDefinition) { bool hasStaticFieldsWithStartingValues = classDefinition.Fields .Where<FieldDeclaration>(fd => fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) .Count() > 0; if (hasStaticFieldsWithStartingValues) { if (classDefinition.StaticConstructor == null) { classDefinition.StaticConstructor = new ConstructorDefinition(null, new Token[0], new Expression[0], new Expression[0], new Executable[0], null, classDefinition); } List<Executable> staticFieldInitializers = new List<Executable>(); foreach (FieldDeclaration fd in classDefinition.Fields) { if (fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) { Executable assignment = new Assignment(new FieldReference(fd.FirstToken, fd, classDefinition), fd.NameToken, "=", fd.DefaultValue, classDefinition); staticFieldInitializers.Add(assignment); } } staticFieldInitializers.AddRange(classDefinition.StaticConstructor.Code); classDefinition.StaticConstructor.Code = staticFieldInitializers.ToArray(); } if (classDefinition.StaticConstructor != null) { // All static field initializers are added here. this.CompileConstructor(parser, buffer, classDefinition.StaticConstructor); } this.CompileConstructor(parser, buffer, classDefinition.Constructor); foreach (FunctionDefinition fd in classDefinition.Methods) { int pc = buffer.Size; fd.FinalizedPC = pc; this.CompileFunctionDefinition(parser, buffer, fd, true); } int classId = classDefinition.ClassID; int baseClassId = classDefinition.BaseClass != null ? classDefinition.BaseClass.ClassID : -1; int nameId = parser.GetId(classDefinition.NameToken.Value); int constructorId = classDefinition.Constructor.FunctionID; int staticConstructorId = classDefinition.StaticConstructor != null ? classDefinition.StaticConstructor.FunctionID : -1; int staticFieldCount = classDefinition.Fields.Where<FieldDeclaration>(fd => fd.IsStaticField).Count(); FieldDeclaration[] regularFields = classDefinition.Fields.Where<FieldDeclaration>(fd => !fd.IsStaticField).ToArray(); FunctionDefinition[] regularMethods = classDefinition.Methods.Where<FunctionDefinition>(fd => !fd.IsStaticMethod).ToArray(); List<int> members = new List<int>(); List<FieldDeclaration> fieldsWithComplexValues = new List<FieldDeclaration>(); foreach (FieldDeclaration fd in regularFields) { int memberId = fd.MemberID; int fieldNameId = parser.GetId(fd.NameToken.Value); int initInstruction; int literalId = 0; if (fd.DefaultValue is ListDefinition && ((ListDefinition)fd.DefaultValue).Items.Length == 0) { initInstruction = 1; } else if (fd.DefaultValue is DictionaryDefinition && ((DictionaryDefinition)fd.DefaultValue).Keys.Length == 0) { initInstruction = 2; } else { initInstruction = 0; literalId = parser.GetLiteralId(fd.DefaultValue); if (literalId == -1) { literalId = parser.GetNullConstant(); fieldsWithComplexValues.Add(fd); } } members.AddRange(new int[] { 0, // flag for field memberId, fieldNameId, initInstruction, literalId}); } foreach (FunctionDefinition fd in regularMethods) { int memberId = fd.MemberID; int methodNameId = parser.GetId(fd.NameToken.Value); int functionId = fd.FunctionID; members.AddRange(new int[] { 1, // flag for method memberId, methodNameId, functionId, 0, // ignored value. It's just here to keep spacing consistent. }); } ByteBuffer initializer = null; if (fieldsWithComplexValues.Count > 0) { initializer = new ByteBuffer(); foreach (FieldDeclaration complexField in fieldsWithComplexValues) { this.CompileExpression(parser, initializer, complexField.DefaultValue, true); initializer.Add(complexField.FirstToken, OpCode.ASSIGN_THIS_STEP, complexField.MemberID); } initializer.Add(null, OpCode.RETURN, 0); } List<int> args = new List<int>() { classId, baseClassId, nameId, constructorId, initializer == null ? 0 : initializer.Size, // jump amount after initialization staticConstructorId, staticFieldCount, }; args.AddRange(members); buffer.Add(classDefinition.FirstToken, OpCode.CLASS_DEFINITION, args.ToArray()); if (initializer != null) { buffer.Concat(initializer); } }