mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
Use two-way mapping for mnemonics -> opcodes
This commit is contained in:
@@ -64,22 +64,22 @@ public class Disassembler
|
||||
{
|
||||
case OpCode.ConstructObject:
|
||||
// COBJ <typeIndex>
|
||||
yield return new Instruction("COBJ", [new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
case OpCode.ConstructObjectIndirect:
|
||||
// COBI <assignmentTypeIndex>
|
||||
yield return new Instruction("COBI", [new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
case OpCode.ConstructObjectParam:
|
||||
// COBP <targetTypeIndex> <constructorIndex>
|
||||
yield return new Instruction("COBP", [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
case OpCode.ConstructFromString:
|
||||
// CSTR <typeIndex> <stringIndex>
|
||||
yield return new Instruction("CSTR", [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
case OpCode.ConstructFromBinary:
|
||||
@@ -88,38 +88,38 @@ public class Disassembler
|
||||
TypeSchema cbinTypeSchema = _loadResult.ImportTables.TypeImports[cbinTypeIndex];
|
||||
object cbinObject = cbinTypeSchema.DecodeBinary(reader);
|
||||
|
||||
yield return new Instruction("CBIN", [new(cbinTypeIndex), new(cbinObject)]);
|
||||
yield return new Instruction(opCode, [new(cbinTypeIndex), new(cbinObject)]);
|
||||
break;
|
||||
|
||||
// TODO
|
||||
|
||||
case OpCode.PropertyInitialize:
|
||||
// PINI <propertyIndex>
|
||||
yield return new Instruction("PINI", [new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
case OpCode.PropertyInitializeIndirect:
|
||||
// PINII <propertyIndex>
|
||||
yield return new Instruction("PINII", [new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
// TODO
|
||||
|
||||
case OpCode.PushConstant:
|
||||
// PSHC <constantIndex>
|
||||
yield return new Instruction("PSHC", [new(reader.ReadUInt16())]);
|
||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
||||
break;
|
||||
|
||||
// TODO
|
||||
|
||||
case OpCode.ReturnValue:
|
||||
// RET
|
||||
yield return new Instruction("RET", []);
|
||||
yield return new Instruction(opCode, []);
|
||||
break;
|
||||
|
||||
case OpCode.ReturnVoid:
|
||||
// RETV
|
||||
yield return new Instruction("RETV", []);
|
||||
yield return new Instruction(opCode, []);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Iris.Asm;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dictionary where entries can be quickly retrieved by their key or value.
|
||||
/// Optimal for one-to-one mappings.
|
||||
/// </summary>
|
||||
public class DoubleDictionary<TLeft, TRight>(int capacity = 0) : ICollection<(TLeft, TRight)>
|
||||
{
|
||||
private readonly Dictionary<TLeft, TRight> _leftDict = new(capacity);
|
||||
private readonly Dictionary<TRight, TLeft> _rightDict = new(capacity);
|
||||
|
||||
public int Count => _leftDict.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public IReadOnlyDictionary<TLeft, TRight> GetLeftDictionary() => _leftDict;
|
||||
public IReadOnlyDictionary<TRight, TLeft> GetRightDictionary() => _rightDict;
|
||||
|
||||
public void Add(TLeft l, TRight r)
|
||||
{
|
||||
_leftDict[l] = r;
|
||||
_rightDict[r] = l;
|
||||
}
|
||||
|
||||
public TRight this[TLeft l] => _leftDict[l];
|
||||
public TLeft this[TRight r] => _rightDict[r];
|
||||
|
||||
public bool Contains(TLeft l) => _leftDict.ContainsKey(l);
|
||||
public bool Contains(TRight r) => _rightDict.ContainsKey(r);
|
||||
|
||||
public bool TryGetRight(TLeft l, out TRight r) => _leftDict.TryGetValue(l, out r);
|
||||
public bool TryGetLeft(TRight r, out TLeft l) => _rightDict.TryGetValue(r, out l);
|
||||
|
||||
public bool Remove(TLeft l)
|
||||
{
|
||||
if (!TryGetRight(l, out var r))
|
||||
return false;
|
||||
_leftDict.Remove(l);
|
||||
|
||||
return _rightDict.Remove(r);
|
||||
}
|
||||
|
||||
public bool Remove(TRight r)
|
||||
{
|
||||
if (!TryGetLeft(r, out var l))
|
||||
return false;
|
||||
_rightDict.Remove(r);
|
||||
|
||||
return _leftDict.Remove(l);
|
||||
}
|
||||
|
||||
public IEnumerator<(TLeft, TRight)> GetEnumerator() => _leftDict
|
||||
.Select(kv => (kv.Key, kv.Value))
|
||||
.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Add((TLeft, TRight) item) => Add(item.Item1, item.Item2);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_leftDict.Clear();
|
||||
_rightDict.Clear();
|
||||
}
|
||||
|
||||
public bool Contains((TLeft, TRight) item)
|
||||
=> _leftDict.TryGetValue(item.Item1, out var r) && r!.Equals(item.Item2);
|
||||
|
||||
public void CopyTo((TLeft, TRight)[] array, int arrayIndex)
|
||||
{
|
||||
var i = arrayIndex;
|
||||
foreach (var pair in this)
|
||||
array[i++] = pair;
|
||||
}
|
||||
|
||||
public bool Remove((TLeft, TRight) item) => Remove(item.Item1) && Remove(item.Item2);
|
||||
}
|
||||
@@ -13,6 +13,11 @@ public static class Lexer
|
||||
|
||||
public static readonly Parser<string> StatementEnd = Parse.Char(';').Return(";").Or(Parse.LineTerminator);
|
||||
|
||||
public static readonly Parser<string> SectionDirective =
|
||||
from _ in Parse.String(".section").Token()
|
||||
from sectionId in Parse.Letter.AtLeastOnce().Text()
|
||||
select sectionId;
|
||||
|
||||
public static readonly Parser<IImport> Import = ParseImport;
|
||||
|
||||
public static readonly Parser<IBodyItem> BodyItem = ParseBodyItem;
|
||||
|
||||
+83
-74
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Iris.Markup;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Iris.Asm;
|
||||
|
||||
@@ -8,90 +7,100 @@ internal static class LexerMaps
|
||||
public static OperationType OperationMnemonicToType(string mnemonic) => OperationMnemonicMap[mnemonic.ToUpperInvariant()];
|
||||
public static OperationType? TryOperationMnemonicToType(string mnemonic)
|
||||
{
|
||||
return OperationMnemonicMap.TryGetValue(mnemonic.ToUpperInvariant(), out var type)
|
||||
return OperationMnemonicMap.TryGetRight(mnemonic.ToUpperInvariant(), out var type)
|
||||
? type : null;
|
||||
}
|
||||
|
||||
public static OpCode MnemonicToOpCode(string mnemonic)
|
||||
{
|
||||
if (MnemonicMap.TryGetValue(mnemonic, out var opCode))
|
||||
if (MnemonicMap.TryGetRight(mnemonic, out var opCode))
|
||||
return opCode;
|
||||
else if (OperationMnemonicMap.TryGetValue(mnemonic, out _))
|
||||
else if (OperationMnemonicMap.TryGetRight(mnemonic, out _))
|
||||
return OpCode.Operation;
|
||||
|
||||
throw new System.ArgumentException($"'{mnemonic}' is not a known UIXA instruction.", nameof(mnemonic));
|
||||
}
|
||||
|
||||
internal static readonly IDictionary<string, OperationType> OperationMnemonicMap = new Dictionary<string, OperationType>
|
||||
public static string GetMnemonic(OpCode opCode, OperationType? opType = null)
|
||||
{
|
||||
["ADD"] = OperationType.MathAdd,
|
||||
["SUB"] = OperationType.MathSubtract,
|
||||
["MUL"] = OperationType.MathMultiply,
|
||||
["DIV"] = OperationType.MathDivide,
|
||||
["MOD"] = OperationType.MathModulus,
|
||||
["NEG"] = OperationType.MathModulus,
|
||||
["AND"] = OperationType.LogicalAnd,
|
||||
["ORR"] = OperationType.LogicalOr,
|
||||
["NOT"] = OperationType.LogicalNot,
|
||||
["REQ"] = OperationType.RelationalEquals,
|
||||
["RNE"] = OperationType.RelationalNotEquals,
|
||||
["RLT"] = OperationType.RelationalLessThan,
|
||||
["RGT"] = OperationType.RelationalGreaterThan,
|
||||
["RLE"] = OperationType.RelationalLessThanEquals,
|
||||
["RGE"] = OperationType.RelationalGreaterThanEquals,
|
||||
["RIS"] = OperationType.RelationalIs,
|
||||
["INC"] = OperationType.PostIncrement,
|
||||
["DEC"] = OperationType.PostDecrement,
|
||||
};
|
||||
if (MnemonicMap.TryGetLeft(opCode, out var mnemonic))
|
||||
return mnemonic;
|
||||
else if (opType.HasValue && OperationMnemonicMap.TryGetLeft(opType.Value, out var operationMnemonic))
|
||||
return operationMnemonic;
|
||||
|
||||
internal static readonly IDictionary<string, OpCode> MnemonicMap = new Dictionary<string, OpCode>
|
||||
{
|
||||
["COBJ"] = OpCode.ConstructObject,
|
||||
["COBI"] = OpCode.ConstructObjectIndirect,
|
||||
["COBP"] = OpCode.ConstructObjectParam,
|
||||
["CSTR"] = OpCode.ConstructFromString,
|
||||
["CBIN"] = OpCode.ConstructFromBinary,
|
||||
["INIT"] = OpCode.InitializeInstance,
|
||||
["INID"] = OpCode.InitializeInstanceIndirect,
|
||||
["LSYM"] = OpCode.LookupSymbol,
|
||||
["WSYM"] = OpCode.WriteSymbol,
|
||||
["WSYP"] = OpCode.WriteSymbolPeek,
|
||||
["CSYM"] = OpCode.ClearSymbol,
|
||||
["PINI"] = OpCode.PropertyInitialize,
|
||||
["PINII"] = OpCode.PropertyInitializeIndirect,
|
||||
["PLAD"] = OpCode.PropertyListAdd,
|
||||
["PDAD"] = OpCode.PropertyDictionaryAdd,
|
||||
["PASS"] = OpCode.PropertyAssign,
|
||||
["PASST"] = OpCode.PropertyAssignStatic,
|
||||
["PGET"] = OpCode.PropertyGet,
|
||||
["PGETP"] = OpCode.PropertyGetPeek,
|
||||
["PGETT"] = OpCode.PropertyGetStatic,
|
||||
["MINV"] = OpCode.MethodInvoke,
|
||||
["MINVP"] = OpCode.MethodInvokePeek,
|
||||
["MINVT"] = OpCode.MethodInvokeStatic,
|
||||
["MINVA"] = OpCode.MethodInvokePushLastParam,
|
||||
["MINVAT"] = OpCode.MethodInvokeStaticPushLastParam, // Avoid using "LT" as suffix
|
||||
["VTC"] = OpCode.VerifyTypeCast,
|
||||
["CON"] = OpCode.ConvertType,
|
||||
["OPR"] = OpCode.Operation, // Generic operation, allow dynamic invocations of operators
|
||||
["ISC"] = OpCode.IsCheck,
|
||||
["ASC"] = OpCode.As,
|
||||
["TYP"] = OpCode.TypeOf,
|
||||
["PSHN"] = OpCode.PushNull,
|
||||
["PSHC"] = OpCode.PushConstant,
|
||||
["PSHT"] = OpCode.PushThis,
|
||||
["DIS"] = OpCode.DiscardValue,
|
||||
["RET"] = OpCode.ReturnValue,
|
||||
["RETV"] = OpCode.ReturnVoid,
|
||||
["JMPF"] = OpCode.JumpIfFalse,
|
||||
["JMPFP"] = OpCode.JumpIfFalsePeek,
|
||||
["JMPTP"] = OpCode.JumpIfTruePeek,
|
||||
["JMPD"] = OpCode.JumpIfDictionaryContains,
|
||||
["JMPNP"] = OpCode.JumpIfNullPeek,
|
||||
["JMP"] = OpCode.Jump,
|
||||
["CLIS"] = OpCode.ConstructListenerStorage,
|
||||
["LIS"] = OpCode.Listen,
|
||||
["DLS"] = OpCode.DestructiveListen,
|
||||
["DBG"] = OpCode.EnterDebugState,
|
||||
};
|
||||
throw new System.ArgumentException($"'{opCode}' is not a known UIXA instruction.", nameof(opCode));
|
||||
}
|
||||
|
||||
internal static readonly DoubleDictionary<string, OperationType> OperationMnemonicMap =
|
||||
[
|
||||
("ADD", OperationType.MathAdd),
|
||||
("SUB", OperationType.MathSubtract),
|
||||
("MUL", OperationType.MathMultiply),
|
||||
("DIV", OperationType.MathDivide),
|
||||
("MOD", OperationType.MathModulus),
|
||||
("NEG", OperationType.MathModulus),
|
||||
("AND", OperationType.LogicalAnd),
|
||||
("ORR", OperationType.LogicalOr),
|
||||
("NOT", OperationType.LogicalNot),
|
||||
("REQ", OperationType.RelationalEquals),
|
||||
("RNE", OperationType.RelationalNotEquals),
|
||||
("RLT", OperationType.RelationalLessThan),
|
||||
("RGT", OperationType.RelationalGreaterThan),
|
||||
("RLE", OperationType.RelationalLessThanEquals),
|
||||
("RGE", OperationType.RelationalGreaterThanEquals),
|
||||
("RIS", OperationType.RelationalIs),
|
||||
("INC", OperationType.PostIncrement),
|
||||
("DEC", OperationType.PostDecrement),
|
||||
];
|
||||
|
||||
internal static readonly DoubleDictionary<string, OpCode> MnemonicMap =
|
||||
[
|
||||
("COBJ", OpCode.ConstructObject),
|
||||
("COBI", OpCode.ConstructObjectIndirect),
|
||||
("COBP", OpCode.ConstructObjectParam),
|
||||
("CSTR", OpCode.ConstructFromString),
|
||||
("CBIN", OpCode.ConstructFromBinary),
|
||||
("INIT", OpCode.InitializeInstance),
|
||||
("INID", OpCode.InitializeInstanceIndirect),
|
||||
("LSYM", OpCode.LookupSymbol),
|
||||
("WSYM", OpCode.WriteSymbol),
|
||||
("WSYP", OpCode.WriteSymbolPeek),
|
||||
("CSYM", OpCode.ClearSymbol),
|
||||
("PINI", OpCode.PropertyInitialize),
|
||||
("PINII", OpCode.PropertyInitializeIndirect),
|
||||
("PLAD", OpCode.PropertyListAdd),
|
||||
("PDAD", OpCode.PropertyDictionaryAdd),
|
||||
("PASS", OpCode.PropertyAssign),
|
||||
("PASST", OpCode.PropertyAssignStatic),
|
||||
("PGET", OpCode.PropertyGet),
|
||||
("PGETP", OpCode.PropertyGetPeek),
|
||||
("PGETT", OpCode.PropertyGetStatic),
|
||||
("MINV", OpCode.MethodInvoke),
|
||||
("MINVP", OpCode.MethodInvokePeek),
|
||||
("MINVT", OpCode.MethodInvokeStatic),
|
||||
("MINVA", OpCode.MethodInvokePushLastParam),
|
||||
("MINVAT", OpCode.MethodInvokeStaticPushLastParam), // Avoid using "LT" as suffix
|
||||
("VTC", OpCode.VerifyTypeCast),
|
||||
("CON", OpCode.ConvertType),
|
||||
("OPR", OpCode.Operation), // Generic operation, allow dynamic invocations of operators
|
||||
("ISC", OpCode.IsCheck),
|
||||
("ASC", OpCode.As),
|
||||
("TYP", OpCode.TypeOf),
|
||||
("PSHN", OpCode.PushNull),
|
||||
("PSHC", OpCode.PushConstant),
|
||||
("PSHT", OpCode.PushThis),
|
||||
("DIS", OpCode.DiscardValue),
|
||||
("RET", OpCode.ReturnValue),
|
||||
("RETV", OpCode.ReturnVoid),
|
||||
("JMPF", OpCode.JumpIfFalse),
|
||||
("JMPFP", OpCode.JumpIfFalsePeek),
|
||||
("JMPTP", OpCode.JumpIfTruePeek),
|
||||
("JMPD", OpCode.JumpIfDictionaryContains),
|
||||
("JMPNP", OpCode.JumpIfNullPeek),
|
||||
("JMP", OpCode.Jump),
|
||||
("CLIS", OpCode.ConstructListenerStorage),
|
||||
("LIS", OpCode.Listen),
|
||||
("DLS", OpCode.DestructiveListen),
|
||||
("DBG", OpCode.EnterDebugState),
|
||||
];
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Iris.Markup;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.Asm.Models;
|
||||
|
||||
@@ -9,6 +10,15 @@ public interface IImport { }
|
||||
|
||||
public record Instruction(string Mnemonic, IEnumerable<Operand> Operands) : IBodyItem
|
||||
{
|
||||
public Instruction(OpCode opCode, OperationType? operationType, IEnumerable<Operand> Operands)
|
||||
: this(LexerMaps.GetMnemonic(opCode, operationType), Operands)
|
||||
{
|
||||
}
|
||||
public Instruction(OpCode opCode, IEnumerable<Operand> Operands)
|
||||
: this(opCode, null, Operands)
|
||||
{
|
||||
}
|
||||
|
||||
public OpCode OpCode => LexerMaps.MnemonicToOpCode(Mnemonic);
|
||||
public OperationType? OperationType => LexerMaps.TryOperationMnemonicToType(Mnemonic);
|
||||
|
||||
@@ -27,5 +37,13 @@ public record Operand(object Value, string Content = null)
|
||||
|
||||
public record Program(IEnumerable<IImport> Imports, IEnumerable<IBodyItem> Body)
|
||||
{
|
||||
public override string ToString() => string.Join("\r\n", Imports.Select(i => i.ToString()).Concat(Body.Select(b => b.ToString())));
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.AppendJoin("\r\n", Imports.Select(i => i.ToString()));
|
||||
sb.AppendJoin("\r\n", Body.Select(b => b.ToString()));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.Asm;
|
||||
|
||||
internal static class StringBuilderExtensions
|
||||
{
|
||||
#if NETSTANDARD
|
||||
public static StringBuilder AppendJoin<T>(this StringBuilder sb, string? separator, IEnumerable<T> values)
|
||||
{
|
||||
_ = values ?? throw new ArgumentNullException(nameof(values));
|
||||
|
||||
separator ??= string.Empty;
|
||||
using (IEnumerator<T> en = values.GetEnumerator())
|
||||
{
|
||||
if (!en.MoveNext())
|
||||
{
|
||||
return sb;
|
||||
}
|
||||
|
||||
T value = en.Current;
|
||||
if (value != null)
|
||||
{
|
||||
sb.Append(value.ToString());
|
||||
}
|
||||
|
||||
while (en.MoveNext())
|
||||
{
|
||||
sb.Append(separator);
|
||||
value = en.Current;
|
||||
if (value != null)
|
||||
{
|
||||
sb.Append(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user