private DMReference ReadReference(BinaryReader reader) { DMReference.Type refType = (DMReference.Type)reader.ReadByte(); switch (refType) { case DMReference.Type.Argument: return(DMReference.CreateArgument(reader.ReadByte())); case DMReference.Type.Local: return(DMReference.CreateLocal(reader.ReadByte())); case DMReference.Type.Global: return(DMReference.CreateGlobal(reader.ReadInt32())); case DMReference.Type.GlobalProc: return(DMReference.CreateGlobalProc(reader.ReadInt32())); case DMReference.Type.Field: return(DMReference.CreateField(Program.CompiledJson.Strings[reader.ReadInt32()])); case DMReference.Type.SrcField: return(DMReference.CreateSrcField(Program.CompiledJson.Strings[reader.ReadInt32()])); case DMReference.Type.Proc: return(DMReference.CreateProc(Program.CompiledJson.Strings[reader.ReadInt32()])); case DMReference.Type.SrcProc: return(DMReference.CreateSrcProc(Program.CompiledJson.Strings[reader.ReadInt32()])); default: return(new DMReference() { RefType = refType }); } }
public DMReference ReadReference() { DMReference.Type refType = (DMReference.Type)ReadByte(); switch (refType) { case DMReference.Type.Local: return(DMReference.CreateLocal(ReadByte())); case DMReference.Type.Global: return(DMReference.CreateGlobal(ReadInt())); case DMReference.Type.Field: return(DMReference.CreateField(ReadString())); case DMReference.Type.SrcField: return(DMReference.CreateSrcField(ReadString())); case DMReference.Type.Proc: return(DMReference.CreateProc(ReadString())); case DMReference.Type.GlobalProc: return(DMReference.CreateGlobalProc(ReadString())); case DMReference.Type.SrcProc: return(DMReference.CreateSrcProc(ReadString())); case DMReference.Type.Src: return(DMReference.Src); case DMReference.Type.Self: return(DMReference.Self); case DMReference.Type.Usr: return(DMReference.Usr); case DMReference.Type.Args: return(DMReference.Args); case DMReference.Type.SuperProc: return(DMReference.SuperProc); case DMReference.Type.ListIndex: return(DMReference.ListIndex); default: throw new Exception($"Invalid reference type {refType}"); } }
public bool IsNullDereference(DMReference reference) { switch (reference.RefType) { case DMReference.Type.Proc: case DMReference.Type.Field: { if (Peek() == DreamValue.Null) { Pop(); return(true); } return(false); } case DMReference.Type.ListIndex: { DreamValue list = _stack[_stackIndex - 2]; if (list == DreamValue.Null) { Pop(); Pop(); return(true); } return(false); } default: throw new Exception($"Invalid dereference type {reference.RefType}"); } }
public void PopReference(DMReference reference) { switch (reference.RefType) { case DMReference.Type.Src: case DMReference.Type.Usr: case DMReference.Type.Self: case DMReference.Type.Global: case DMReference.Type.GlobalProc: case DMReference.Type.Argument: case DMReference.Type.Local: case DMReference.Type.Args: case DMReference.Type.SrcField: return; case DMReference.Type.Field: Pop(); return; case DMReference.Type.ListIndex: Pop(); Pop(); return; default: throw new Exception($"Cannot pop stack values of reference type {reference.RefType}"); } }
public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference) { proc.PushReferenceValue(reference); RHS.EmitPushValue(dmObject, proc); proc.BitShiftRight(); proc.Assign(reference); }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { if (!DMObjectTree.TryGetGlobalProc(_name, out _)) { throw new CompileErrorException(Location, $"There is no global proc named \"{_name}\""); } return(DMReference.CreateGlobalProc(_name), false); }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { if (LocalVar.IsParameter) { return(DMReference.CreateArgument(LocalVar.Id), false); } else { return(DMReference.CreateLocal(LocalVar.Id), false); } }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { if (dmObject.HasProc(_identifier)) { return(DMReference.CreateSrcProc(_identifier), false); } else if (DMObjectTree.TryGetGlobalProc(_identifier, out _)) { return(DMReference.CreateGlobalProc(_identifier), false); } throw new CompileErrorException(Location, $"Type {dmObject.Path} does not have a proc named \"{_identifier}\""); }
public void AssignReference(DMReference reference, DreamValue value) { switch (reference.RefType) { case DMReference.Type.Self: Result = value; break; case DMReference.Type.Argument: _localVariables[reference.Index] = value; break; case DMReference.Type.Local: _localVariables[ArgumentCount + reference.Index] = value; break; case DMReference.Type.SrcField: Instance.SetVariable(reference.Name, value); break; case DMReference.Type.Global: DreamManager.Globals[reference.Index] = value; break; case DMReference.Type.Src: //TODO: src can be assigned to non-DreamObject values if (!value.TryGetValueAsDreamObject(out Instance)) { throw new Exception($"Cannot assign src to {value}"); } break; case DMReference.Type.Field: { DreamValue owner = Pop(); if (!owner.TryGetValueAsDreamObject(out var ownerObj) || ownerObj == null) { throw new Exception($"Cannot assign field \"{reference.Name}\" on {owner}"); } ownerObj.SetVariable(reference.Name, value); break; } case DMReference.Type.ListIndex: { DreamValue index = Pop(); DreamValue list = Pop(); if (!list.TryGetValueAsDreamList(out var listObj)) { throw new Exception($"Cannot assign to index {index} of {list}"); } listObj.SetValue(index, value); break; } default: throw new Exception($"Cannot assign to reference type {reference.RefType}"); } }
public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference) { string skipLabel = proc.NewLabelName(); string endLabel = proc.NewLabelName(); proc.PushReferenceValue(reference); proc.JumpIfTrue(skipLabel); RHS.EmitPushValue(dmObject, proc); proc.Assign(reference); proc.Jump(endLabel); proc.AddLabel(skipLabel); proc.PushReferenceValue(reference); proc.AddLabel(endLabel); }
public void ProcessProcDefinition(DMASTProcDefinition procDefinition) { if (procDefinition.Body == null) { return; } foreach (DMASTDefinitionParameter parameter in procDefinition.Parameters) { string parameterName = parameter.Name; if (!_proc.TryAddLocalVariable(parameterName, parameter.ObjectType)) { DMCompiler.Error(new CompilerError(procDefinition.Location, $"Duplicate argument \"{parameterName}\" on {procDefinition.ObjectPath}/proc/{procDefinition.Name}()")); continue; } if (parameter.Value != null) //Parameter has a default value { string afterDefaultValueCheck = _proc.NewLabelName(); DMReference parameterRef = _proc.GetLocalVariableReference(parameterName); //Don't set parameter to default if not null _proc.PushReferenceValue(parameterRef); _proc.IsNull(); _proc.JumpIfFalse(afterDefaultValueCheck); //Set default try { DMExpression.Emit(_dmObject, _proc, parameter.Value, parameter.ObjectType); } catch (CompileErrorException e) { DMCompiler.Error(e.Error); } _proc.Assign(parameterRef); _proc.Pop(); _proc.AddLabel(afterDefaultValueCheck); } } ProcessBlockInner(procDefinition.Body); _proc.ResolveLabels(); }
public override void EmitPushValue(DMObject dmObject, DMProc proc) { _path.EmitPushValue(dmObject, proc); if (_container != null) { _container.EmitPushValue(dmObject, proc); } else { if (DMCompiler.Settings.NoStandard) { throw new CompileErrorException(Location, "Implicit locate() container is not available with --no-standard"); } DMReference world = DMReference.CreateGlobal(dmObject.GetGlobalVariableId("world").Value); proc.PushReferenceValue(world); } proc.Locate(); }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { _expr.EmitPushValue(dmObject, proc); return(DMReference.CreateField(PropertyName), _conditional); }
public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference) { proc.Decrement(reference); }
public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference) { proc.PushFloat(1); proc.Remove(reference); }
public DreamValue GetReferenceValue(DMReference reference, bool peek = false) { switch (reference.RefType) { case DMReference.Type.Src: return(new(Instance)); case DMReference.Type.Usr: return(new(Usr)); case DMReference.Type.Self: return(Result); case DMReference.Type.Global: return(DreamManager.Globals[reference.Index]); case DMReference.Type.Argument: return(_localVariables[reference.Index]); case DMReference.Type.Local: return(_localVariables[ArgumentCount + reference.Index]); case DMReference.Type.Args: { DreamList argsList = DreamList.Create(ArgumentCount); for (int i = 0; i < ArgumentCount; i++) { argsList.AddValue(_localVariables[i]); } argsList.ValueAssigned += (DreamList argsList, DreamValue key, DreamValue value) => { if (!key.TryGetValueAsInteger(out int argIndex)) { throw new Exception($"Cannot index args with {key}"); } if (argIndex > ArgumentCount) { throw new Exception($"Args index {argIndex} is too large"); } _localVariables[argIndex - 1] = value; }; return(new(argsList)); } case DMReference.Type.Field: { DreamValue owner = peek ? Peek() : Pop(); if (!owner.TryGetValueAsDreamObject(out var ownerObj) || ownerObj == null) { throw new Exception($"Cannot get field \"{reference.Name}\" from {owner}"); } if (!ownerObj.TryGetVariable(reference.Name, out var fieldValue)) { throw new Exception($"Type {ownerObj.ObjectDefinition.Type} has no field called \"{reference.Name}\""); } return(fieldValue); } case DMReference.Type.SrcField: { if (!Instance.TryGetVariable(reference.Name, out var fieldValue)) { throw new Exception($"Type {Instance.ObjectDefinition.Type} has no field called \"{reference.Name}\""); } return(fieldValue); } case DMReference.Type.ListIndex: { DreamValue index = peek ? _stack[_stackIndex - 1] : Pop(); DreamValue indexing = peek ? _stack[_stackIndex - 2] : Pop(); if (indexing.TryGetValueAsDreamList(out var listObj)) { return(listObj.GetValue(index)); } else if (indexing.TryGetValueAsString(out string strValue)) { if (!index.TryGetValueAsInteger(out int strIndex)) { throw new Exception($"Attempted to index string with {index}"); } char c = strValue[strIndex - 1]; return(new DreamValue(Convert.ToString(c))); } else { throw new Exception($"Cannot get index {index} of {indexing}"); } } default: throw new Exception($"Cannot get value of reference type {reference.RefType}"); } }
public abstract void EmitOp(DMObject dmObject, DMProc proc, DMReference reference);
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { return(DMReference.CreateSrcField(Variable.Name), false); }
public DreamValue GetReferenceValue(DMReference reference, bool peek = false) { switch (reference.RefType) { case DMReference.Type.Src: return(new(Instance)); case DMReference.Type.Usr: return(new(Usr)); case DMReference.Type.Self: return(Result); case DMReference.Type.Global: return(DreamManager.Globals[reference.GlobalId]); case DMReference.Type.Local: return(LocalVariables[reference.LocalId]); case DMReference.Type.Args: { DreamList argsList = Arguments.CreateDreamList(); argsList.ValueAssigned += (DreamList argsList, DreamValue key, DreamValue value) => { switch (key.Type) { case DreamValue.DreamValueType.String: { string argumentName = key.GetValueAsString(); Arguments.NamedArguments[argumentName] = value; LocalVariables[Proc.ArgumentNames.IndexOf(argumentName)] = value; break; } case DreamValue.DreamValueType.Float: { int argumentIndex = key.GetValueAsInteger() - 1; Arguments.OrderedArguments[argumentIndex] = value; LocalVariables[argumentIndex] = value; break; } default: throw new Exception("Invalid key used on an args list"); } }; return(new(argsList)); } case DMReference.Type.Field: { DreamValue owner = peek ? Peek() : Pop(); if (!owner.TryGetValueAsDreamObject(out var ownerObj) || ownerObj == null) { throw new Exception($"Cannot get field \"{reference.FieldName}\" from {owner}"); } if (!ownerObj.TryGetVariable(reference.FieldName, out var fieldValue)) { throw new Exception($"Type {ownerObj.ObjectDefinition.Type} has no field called \"{reference.FieldName}\""); } return(fieldValue); } case DMReference.Type.SrcField: { if (!Instance.TryGetVariable(reference.FieldName, out var fieldValue)) { throw new Exception($"Type {Instance.ObjectDefinition.Type} has no field called \"{reference.FieldName}\""); } return(fieldValue); } case DMReference.Type.ListIndex: { DreamValue index = peek ? _stack[_stackIndex - 1] : Pop(); DreamValue list = peek ? _stack[_stackIndex - 2] : Pop(); if (!list.TryGetValueAsDreamList(out var listObj)) { throw new Exception($"Cannot get index {index} of {list}"); } return(listObj.GetValue(index)); } default: throw new Exception($"Cannot get value of reference type {reference.RefType}"); } }
public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference) { RHS.EmitPushValue(dmObject, proc); proc.ModulusReference(reference); }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { DMProc globalProc = GetProc(); return(DMReference.CreateGlobalProc(globalProc.Id), false); }
public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc) { return(DMReference.CreateLocal(LocalVar.Id), false); }
public string Decompile() { List <DecompiledOpcode> decompiled = new(); HashSet <int> labeledPositions = new(); MemoryStream stream = new MemoryStream(Bytecode); BinaryReader binaryReader = new BinaryReader(stream); long position = 0; DreamProcOpcode opcode; while ((opcode = (DreamProcOpcode)stream.ReadByte()) != (DreamProcOpcode)(-1)) { StringBuilder text = new StringBuilder(); text.Append(opcode); text.Append(" "); switch (opcode) { case DreamProcOpcode.FormatString: case DreamProcOpcode.PushString: { text.Append('"'); text.Append(Program.CompiledJson.Strings[binaryReader.ReadInt32()]); text.Append('"'); break; } case DreamProcOpcode.PushResource: { text.Append('\''); text.Append(Program.CompiledJson.Strings[binaryReader.ReadInt32()]); text.Append('\''); break; } case DreamProcOpcode.Prompt: text.Append((DMValueType)binaryReader.ReadInt32()); break; case DreamProcOpcode.PushFloat: text.Append(binaryReader.ReadSingle()); break; case DreamProcOpcode.Call: case DreamProcOpcode.Assign: case DreamProcOpcode.Append: case DreamProcOpcode.Remove: case DreamProcOpcode.Combine: case DreamProcOpcode.Increment: case DreamProcOpcode.Decrement: case DreamProcOpcode.Mask: case DreamProcOpcode.MultiplyReference: case DreamProcOpcode.DivideReference: case DreamProcOpcode.BitXorReference: case DreamProcOpcode.Enumerate: case DreamProcOpcode.PushReferenceValue: text.Append(ReadReference(binaryReader).ToString()); break; case DreamProcOpcode.CreateList: case DreamProcOpcode.CreateAssociativeList: case DreamProcOpcode.PickWeighted: case DreamProcOpcode.PickUnweighted: text.Append(binaryReader.ReadInt32()); break; case DreamProcOpcode.JumpIfNullDereference: { DMReference reference = ReadReference(binaryReader); int jumpPosition = binaryReader.ReadInt32(); labeledPositions.Add(jumpPosition); text.Append(reference.ToString()); text.Append(" "); text.Append(jumpPosition); break; } case DreamProcOpcode.Initial: case DreamProcOpcode.IsSaved: case DreamProcOpcode.PushPath: text.Append(Program.CompiledJson.Strings[binaryReader.ReadInt32()]); break; case DreamProcOpcode.Spawn: case DreamProcOpcode.BooleanOr: case DreamProcOpcode.BooleanAnd: case DreamProcOpcode.SwitchCase: case DreamProcOpcode.SwitchCaseRange: case DreamProcOpcode.Jump: case DreamProcOpcode.JumpIfFalse: case DreamProcOpcode.JumpIfTrue: { int jumpPosition = binaryReader.ReadInt32(); labeledPositions.Add(jumpPosition); text.Append(jumpPosition); break; } case DreamProcOpcode.PushType: text.Append(Program.CompiledJson.Types[binaryReader.ReadInt32()].Path); break; case DreamProcOpcode.PushArguments: { int argCount = binaryReader.ReadInt32(); int namedCount = binaryReader.ReadInt32(); text.Append(argCount); for (int i = 0; i < argCount; i++) { text.Append(" "); DreamProcOpcodeParameterType argType = (DreamProcOpcodeParameterType)binaryReader.ReadByte(); if (argType == DreamProcOpcodeParameterType.Named) { string argName = Program.CompiledJson.Strings[binaryReader.ReadInt32()]; text.Append("Named(" + argName + ")"); } else { text.Append("Unnamed"); } } break; } } decompiled.Add(new DecompiledOpcode(position, text.ToString())); position = stream.Position; } StringBuilder result = new StringBuilder(); foreach (DecompiledOpcode decompiledOpcode in decompiled) { if (labeledPositions.Contains((int)decompiledOpcode.Position)) { result.Append(decompiledOpcode.Position); } result.Append('\t'); result.AppendLine(decompiledOpcode.Text); } return(result.ToString()); }