11using System . Collections . Immutable ;
2+ using System . Diagnostics ;
23using System . Text ;
4+ using System . Xml ;
35
46namespace MagesScriptTool ;
57
68sealed class InstructionEncoding {
7- readonly ImmutableTree < byte , InstructionSpec > _tree ;
8- readonly ImmutableDictionary < string , InstructionSpec > _table ;
9+ readonly ImmutableTree < byte , VmInstructionSpec > _opcodeTree ;
10+ readonly ImmutableDictionary < string , InstructionSpec > _specTable ;
911
10- InstructionEncoding ( ImmutableTree < byte , InstructionSpec > tree , ImmutableDictionary < string , InstructionSpec > table ) {
11- _tree = tree ;
12- _table = table ;
12+ InstructionEncoding ( ImmutableTree < byte , VmInstructionSpec > opcodeTree , ImmutableDictionary < string , InstructionSpec > specTable ) {
13+ _opcodeTree = opcodeTree ;
14+ _specTable = specTable ;
1315 }
1416
1517 public void Encode ( Stream stream , Instruction instruction ) {
16- InstructionSpec spec = _table [ instruction . Name ] ;
17- PutBytes ( stream , spec . Opcode . AsSpan ( ) ) ;
18+ InstructionSpec spec = _specTable [ instruction . Name ] ;
19+ if ( spec is VmInstructionSpec vmInstructionSpec ) {
20+ PutBytes ( stream , vmInstructionSpec . Opcode . AsSpan ( ) ) ;
21+ }
1822 ImmutableArray < OperandKind > kinds = spec . Operands ;
1923 ImmutableArray < ExpressionNode > operands = instruction . Operands ;
2024 if ( operands . Length != kinds . Length ) {
@@ -32,9 +36,22 @@ public Instruction Decode(Stream stream) {
3236 foreach ( OperandKind operandSpec in operandSpecs ) {
3337 operands . Add ( DecodeOperand ( stream , operandSpec ) ) ;
3438 }
35- return new ( spec . Name , [ ..operands ] ) ;
39+ return new ( spec . Name , [ ..operands ] ) ;
3640 }
3741
42+ public Instruction Decode ( Stream stream , string dataDirective ) {
43+ DataDirectiveSpec spec = _specTable . GetValueOrDefault ( dataDirective ) switch {
44+ DataDirectiveSpec dataDirectiveSpec => dataDirectiveSpec ,
45+ _ => throw new Exception ( $ "Unrecognized data directive name: { dataDirective } ")
46+ } ;
47+
48+ ImmutableArray < OperandKind > operandSpecs = spec . Operands ;
49+ List < ExpressionNode > operands = [ ] ;
50+ foreach ( OperandKind operandSpec in operandSpecs ) {
51+ operands . Add ( DecodeOperand ( stream , operandSpec ) ) ;
52+ }
53+ return new ( spec . Name , [ ..operands ] ) ;
54+ }
3855 static void EncodeOperand ( Stream stream , OperandKind kind , ExpressionNode operand ) {
3956 switch ( kind ) {
4057 case OperandKind . Expr : {
@@ -45,6 +62,7 @@ static void EncodeOperand(Stream stream, OperandKind kind, ExpressionNode operan
4562 EncodeOperandInt8 ( stream , operand ) ;
4663 break ;
4764 }
65+ case OperandKind . UInt16 :
4866 case OperandKind . Int16 : {
4967 EncodeOperandInt16 ( stream , operand ) ;
5068 break ;
@@ -95,17 +113,17 @@ static void PutBytes(Stream stream, ReadOnlySpan<byte> data) {
95113 stream . Write ( data ) ;
96114 }
97115
98- InstructionSpec DecodeOpcode ( Stream stream ) {
116+ VmInstructionSpec DecodeOpcode ( Stream stream ) {
99117 long start = stream . Position ;
100- ImmutableTree < byte , InstructionSpec > cursor = _tree ;
118+ ImmutableTree < byte , VmInstructionSpec > cursor = _opcodeTree ;
101119 while ( true ) {
102120 byte b = GetByte ( stream ) ;
103- ImmutableTree < byte , InstructionSpec > ? next = cursor [ b ] ;
121+ ImmutableTree < byte , VmInstructionSpec > ? next = cursor [ b ] ;
104122 if ( next is null ) {
105123 throw new Exception ( $ "Unrecognized instruction at { start } .") ;
106124 }
107125 cursor = next ;
108- if ( cursor . Value is InstructionSpec opcodeSpec ) {
126+ if ( cursor . Value is VmInstructionSpec opcodeSpec ) {
109127 return opcodeSpec ;
110128 }
111129 }
@@ -115,6 +133,7 @@ static ExpressionNode DecodeOperand(Stream stream, OperandKind kind) {
115133 return kind switch {
116134 OperandKind . Expr => ExpressionEncoding . Decode ( stream ) ,
117135 OperandKind . Int8 => DecodeOperandInt8 ( stream ) ,
136+ OperandKind . UInt16 => DecodeOperandUInt16 ( stream ) ,
118137 OperandKind . Int16 => DecodeOperandInt16 ( stream ) ,
119138 OperandKind . Int32 => DecodeOperandInt32 ( stream ) ,
120139 OperandKind . Str => DecodeOperandStr ( stream ) ,
@@ -138,6 +157,13 @@ static ExpressionNodeNumber DecodeOperandInt8(Stream stream) {
138157 return new ( value ) ;
139158 }
140159
160+ static ExpressionNodeNumber DecodeOperandUInt16 ( Stream stream ) {
161+ int value = 0 ;
162+ value |= GetByte ( stream ) << 0 ;
163+ value |= GetByte ( stream ) << 8 ;
164+ return new ( value ) ;
165+ }
166+
141167 static ExpressionNodeNumber DecodeOperandInt16 ( Stream stream ) {
142168 int value = 0 ;
143169 value |= GetByte ( stream ) << 0 ;
@@ -169,10 +195,10 @@ static int SignExtend(int value, int length) {
169195 return value | ~ ( sign - 1 ) ;
170196 }
171197
172- public static InstructionEncoding BuildFrom ( ImmutableArray < InstructionSpec > opcodeSpecs ) {
173- ImmutableTree < byte , InstructionSpec > tree = BuildOpcodeTree ( opcodeSpecs ) ;
198+ public static InstructionEncoding BuildFrom ( ImmutableArray < InstructionSpec > specs ) {
199+ ImmutableTree < byte , VmInstructionSpec > tree = BuildOpcodeTree ( specs ) ;
174200 Dictionary < string , InstructionSpec > table = [ ] ;
175- foreach ( InstructionSpec spec in opcodeSpecs ) {
201+ foreach ( InstructionSpec spec in specs ) {
176202 if ( table . ContainsKey ( spec . Name ) ) {
177203 throw new Exception ( $ "Duplicate instruction name: { spec . Name } .") ;
178204 }
@@ -181,14 +207,16 @@ public static InstructionEncoding BuildFrom(ImmutableArray<InstructionSpec> opco
181207 return new ( tree , table . ToImmutableDictionary ( ) ) ;
182208 }
183209
184- static ImmutableTree < byte , InstructionSpec > BuildOpcodeTree ( ImmutableArray < InstructionSpec > specs ) {
185- Tree < byte , InstructionSpec > tree = new ( ) ;
210+ static ImmutableTree < byte , VmInstructionSpec > BuildOpcodeTree ( ImmutableArray < InstructionSpec > specs ) {
211+ Tree < byte , VmInstructionSpec > tree = new ( ) ;
186212 foreach ( InstructionSpec spec in specs ) {
187- ImmutableArray < byte > opcode = spec . Opcode ;
213+ if ( spec is not VmInstructionSpec ) continue ;
214+ VmInstructionSpec vmInstructionSpec = ( VmInstructionSpec ) spec ;
215+ ImmutableArray < byte > opcode = vmInstructionSpec . Opcode ;
188216 if ( opcode . Length == 0 ) {
189217 throw new Exception ( $ "Empty opcode: { spec . Name } .") ;
190218 }
191- Tree < byte , InstructionSpec > cursor = tree ;
219+ Tree < byte , VmInstructionSpec > cursor = tree ;
192220 for ( int i = 0 ; i < opcode . Length ; i ++ ) {
193221 if ( cursor . HasValue ) {
194222 throw new Exception ( $ "Duplicate opcode prefix: { Convert . ToHexString ( opcode . AsSpan ( ) [ ..i ] ) } .") ;
@@ -201,7 +229,7 @@ static ImmutableTree<byte, InstructionSpec> BuildOpcodeTree(ImmutableArray<Instr
201229 if ( cursor . HasValue ) {
202230 throw new Exception ( $ "Duplicate opcode: { Convert . ToHexString ( opcode . AsSpan ( ) ) } .") ;
203231 }
204- cursor . Value = spec ;
232+ cursor . Value = vmInstructionSpec ;
205233 }
206234 return tree . ToImmutableTree ( ) ;
207235 }
0 commit comments