/// <summary> /// Inject a compiled sub-unit into this writer /// References to string constants will be recalculated /// </summary> public void Merge(NanCodeWriter fragment) { var codes = fragment._opcodes; var strings = fragment._stringTable; AddSymbols(fragment._symbols); foreach (var code in codes) { var type = NanTags.TypeOf(code); switch (type) { case DataType.Invalid: throw new Exception("Invalid opcode when merging"); case DataType.ValInt32: case DataType.ValUInt32: case DataType.VariableRef: case DataType.Number: case DataType.Opcode: _opcodes.Add(code); break; case DataType.PtrString: case DataType.PtrStaticString: NanTags.DecodePointer(code, out var target, out _); LiteralString(strings[(int)target]); break; // all other types are only expected at runtime (so far) default: throw new Exception("Unexpected opcode when merging"); } } }
/// <summary> /// Write opcodes and data section to stream /// References to string constants will be recalculated /// </summary> public void WriteToStream(Stream output) { // a string is [NanTag(UInt32): byte length] [string bytes, padded to 8 byte chunks] // 1) Calculate the string table size var dataLength = _stringTable.Select(CalculatePaddedSize).Sum() + _stringTable.Count; // 2) Write a jump command to skip the table var jumpCode = NanTags.EncodeLongOpcode('c', 's', (uint)dataLength); WriteCode(output, jumpCode); // 3) Write the strings, with a mapping dictionary long location = 1; // counting initial jump as 0 var mapping = new Dictionary <long, long>(); // original index, final memory location for (var index = 0; index < _stringTable.Count; index++) { var staticStr = _stringTable[index]; var bytes = Encoding.ASCII.GetBytes(staticStr); var chunks = CalculatePaddedSize(staticStr); var padSize = (chunks * 8) - bytes.Length; mapping.Add(index, location); var headerOpCode = NanTags.EncodeUInt32((uint)bytes.Length); WriteCode(output, headerOpCode); location++; output.Write(bytes, 0, bytes.Length); location += chunks; for (int p = 0; p < padSize; p++) { output.WriteByte(0); } } // 4) Write the op-codes foreach (var code in _opcodes) { var type = NanTags.TypeOf(code); switch (type) { case DataType.PtrString: case DataType.PtrStaticString: NanTags.DecodePointer(code, out var original, out _); var final = mapping[original]; WriteCode(output, NanTags.EncodePointer(final, DataType.PtrStaticString)); break; default: WriteCode(output, code); break; } } output.Flush(); }