Example #1
0
        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
                });
            }
        }
Example #2
0
        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}");
            }
        }
Example #3
0
        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}");
            }
        }
Example #4
0
        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}");
            }
        }
Example #5
0
 public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference)
 {
     proc.PushReferenceValue(reference);
     RHS.EmitPushValue(dmObject, proc);
     proc.BitShiftRight();
     proc.Assign(reference);
 }
Example #6
0
        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);
        }
Example #7
0
 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);
     }
 }
Example #8
0
        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}\"");
        }
Example #9
0
        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}");
            }
        }
Example #10
0
        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);
        }
Example #11
0
        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();
        }
Example #12
0
        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();
        }
Example #13
0
 public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc)
 {
     _expr.EmitPushValue(dmObject, proc);
     return(DMReference.CreateField(PropertyName), _conditional);
 }
Example #14
0
 public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference)
 {
     proc.Decrement(reference);
 }
Example #15
0
 public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference)
 {
     proc.PushFloat(1);
     proc.Remove(reference);
 }
Example #16
0
        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}");
            }
        }
Example #17
0
 public abstract void EmitOp(DMObject dmObject, DMProc proc, DMReference reference);
Example #18
0
 public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc)
 {
     return(DMReference.CreateSrcField(Variable.Name), false);
 }
Example #19
0
        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}");
            }
        }
Example #20
0
 public override void EmitOp(DMObject dmObject, DMProc proc, DMReference reference)
 {
     RHS.EmitPushValue(dmObject, proc);
     proc.ModulusReference(reference);
 }
Example #21
0
        public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc)
        {
            DMProc globalProc = GetProc();

            return(DMReference.CreateGlobalProc(globalProc.Id), false);
        }
Example #22
0
 public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc)
 {
     return(DMReference.CreateLocal(LocalVar.Id), false);
 }
Example #23
0
        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());
        }