Beispiel #1
0
        public override void EmitPushValue(DMObject dmObject, DMProc proc)
        {
            switch (_expr)
            {
            case Field field:
                field.EmitPushIsSaved(proc);
                return;

            case Dereference dereference:
                dereference.EmitPushIsSaved(dmObject, proc);
                return;

            case Local:
                proc.PushFloat(0);
                return;

            case ListIndex:
                proc.PushFloat(0);
                // Silent in BYOND
                DMCompiler.Warning(new CompilerWarning(_expr.Location, "calling issaved() on a list index is always false"));
                return;

            default:
                throw new CompileErrorException(Location, $"can't get saved value of {_expr}");
            }
        }
Beispiel #2
0
 public override (DMReference Reference, bool Conditional) EmitReference(DMObject dmObject, DMProc proc)
 {
     if (!proc.IsOverride)
     {
         DMCompiler.Warning(new CompilerWarning(Location, "Calling parents via ..() in a proc definition does nothing"));
     }
     return(DMReference.SuperProc, false);
 }
Beispiel #3
0
 public override bool TryAsJsonRepresentation(out object json)
 {
     json = null;
     if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
     {
         DMCompiler.Warning(new CompilerWarning(Location, "DMM overrides for newlist() are not implemented"));
     }
     return(true); //TODO
 }
Beispiel #4
0
 public override void EmitPushInitial(DMObject dmObject, DMProc proc)
 {
     // This happens silently in BYOND
     // TODO Support "vars" actually pushing initial() correctly
     if (_expr is Dereference deref && deref.PropertyName != "vars")
     {
         DMCompiler.Warning(new CompilerWarning(Location, "calling initial() on a list index returns the current value"));
     }
     EmitPushValue(dmObject, proc);
 }
Beispiel #5
0
        public bool IsSaved()
        {
            // Silent in BYOND
            // TODO Support "vars" actually pushing issaved() correctly
            if (_expr is Dereference deref && deref.PropertyName != "vars")
            {
                DMCompiler.Warning(new CompilerWarning(_expr.Location, "calling issaved() on a list index is always false"));
                return(false);
            }

            return(true);
        }
Beispiel #6
0
        public void ProcessStatementForList(DMASTProcStatementForList statementForList)
        {
            DMExpression.Emit(_dmObject, _proc, statementForList.List);
            _proc.CreateListEnumerator();
            _proc.StartScope();
            {
                if (statementForList.Initializer != null)
                {
                    ProcessStatement(statementForList.Initializer);
                }

                string loopLabel = _proc.NewLabelName();
                _proc.LoopStart(loopLabel);
                {
                    DMExpression outputVariable = DMExpression.Create(_dmObject, _proc, statementForList.Variable);
                    (DMReference outputRef, _) = outputVariable.EmitReference(_dmObject, _proc);
                    _proc.Enumerate(outputRef);
                    _proc.BreakIfFalse();

                    DMASTProcStatementVarDeclaration varDeclaration = statementForList.Initializer as DMASTProcStatementVarDeclaration;
                    if (varDeclaration != null && varDeclaration.Type != null)
                    {
                        //This is terrible but temporary
                        //TODO: See https://github.com/wixoaGit/OpenDream/issues/50
                        var obj = DMObjectTree.GetDMObject(varDeclaration.Type.Value);
                        if (statementForList.List is DMASTIdentifier list && list.Identifier == "world" && !obj.IsSubtypeOf(DreamPath.Atom))
                        {
                            var warn = new CompilerWarning(statementForList.Location, "Cannot currently loop 'in world' for non-ATOM types");
                            DMCompiler.Warning(warn);
                        }
                        DMExpression.Emit(_dmObject, _proc, statementForList.Variable);
                        _proc.PushPath(varDeclaration.Type.Value);
                        _proc.IsType();

                        _proc.ContinueIfFalse();
                    }

                    ProcessBlockInner(statementForList.Body);

                    _proc.LoopContinue(loopLabel);
                    _proc.LoopJumpToStart(loopLabel);
                }
                _proc.LoopEnd();
            }
            _proc.EndScope();
            _proc.DestroyEnumerator();
        }
Beispiel #7
0
        public void VisitDereference(DMASTDereference dereference)
        {
            var expr = DMExpression.Create(_dmObject, _proc, dereference.Expression, _inferredPath);

            if (dereference.Type == DMASTDereference.DereferenceType.Direct && !Dereference.DirectConvertable(expr, dereference))
            {
                if (expr.Path == null)
                {
                    throw new CompileErrorException(dereference.Location, $"Invalid property \"{dereference.Property}\"");
                }

                DMObject dmObject = DMObjectTree.GetDMObject(expr.Path.Value, false);
                if (dmObject == null)
                {
                    throw new CompileErrorException(dereference.Location, $"Type {expr.Path.Value} does not exist");
                }

                var property = dmObject.GetVariable(dereference.Property);
                if (property != null)
                {
                    Result = new Expressions.Dereference(dereference.Location, property.Type, expr, dereference.Conditional, dereference.Property);
                }
                else
                {
                    var globalId = dmObject.GetGlobalVariableId(dereference.Property);
                    if (globalId != null)
                    {
                        property = DMObjectTree.Globals[globalId.Value];
                        Result   = new Expressions.GlobalField(dereference.Location, property.Type, globalId.Value);
                    }
                }

                if (property == null)
                {
                    throw new CompileErrorException(dereference.Location, $"Invalid property \"{dereference.Property}\" on type {dmObject.Path}");
                }

                if ((property.Value?.ValType & DMValueType.Unimplemented) == DMValueType.Unimplemented && !DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(dereference.Location, $"{dmObject.Path}.{dereference.Property} is not implemented and will have unexpected behavior"));
                }
            }
            else
            {
                Result = new Expressions.Dereference(dereference.Location, null, expr, dereference.Conditional, dereference.Property);
            }
        }
Beispiel #8
0
        public override void EmitPushValue(DMObject dmObject, DMProc proc)
        {
            bool weighted = false;

            foreach (PickValue pickValue in _values)
            {
                if (pickValue.Weight != null)
                {
                    weighted = true;
                    break;
                }
            }

            if (weighted)
            {
                if (_values.Length == 1)
                {
                    DMCompiler.Warning(new CompilerWarning(Location, "Weighted pick() with one argument"));
                }

                foreach (PickValue pickValue in _values)
                {
                    DMExpression weight = pickValue.Weight ?? DMExpression.Create(dmObject, proc, new DMASTConstantInteger(Location, 100)); //Default of 100

                    weight.EmitPushValue(dmObject, proc);
                    pickValue.Value.EmitPushValue(dmObject, proc);
                }

                proc.PickWeighted(_values.Length);
            }
            else
            {
                foreach (PickValue pickValue in _values)
                {
                    if (pickValue.Value is Arglist args)
                    {
                        args.EmitPushArglist(dmObject, proc);
                    }
                    else
                    {
                        pickValue.Value.EmitPushValue(dmObject, proc);
                    }
                }

                proc.PickUnweighted(_values.Length);
            }
        }
Beispiel #9
0
 public override void EmitPushInitial(DMObject dmObject, DMProc proc)
 {
     // This happens silently in BYOND
     DMCompiler.Warning(new CompilerWarning(Location, "calling initial() on a local variable returns the current value"));
     EmitPushValue(dmObject, proc);
 }
Beispiel #10
0
        public void ProcessStatementSet(DMASTProcStatementSet statementSet)
        {
            var attribute = statementSet.Attribute.ToLower();

            if (!DMExpression.TryConstant(_dmObject, _proc, statementSet.Value, out var constant))
            {
                throw new CompileErrorException(statementSet.Location, $"{attribute} attribute should be a constant");
            }

            switch (statementSet.Attribute.ToLower())
            {
            case "waitfor": {
                _proc.WaitFor(constant.IsTruthy());
                break;
            }

            case "opendream_unimplemented": {
                if (constant.IsTruthy())
                {
                    _proc.Attributes |= ProcAttributes.Unimplemented;
                }
                else
                {
                    _proc.Attributes &= ~ProcAttributes.Unimplemented;
                }
                break;
            }

            case "hidden":
                if (constant.IsTruthy())
                {
                    _proc.Attributes |= ProcAttributes.Hidden;
                }
                else
                {
                    _proc.Attributes &= ~ProcAttributes.Hidden;
                }

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set hidden is not implemented"));
                }

                break;

            case "popup_menu":
                if (constant.IsTruthy())     // The default is to show it so we flag it if it's hidden
                {
                    _proc.Attributes &= ~ProcAttributes.HidePopupMenu;
                }
                else
                {
                    _proc.Attributes |= ProcAttributes.HidePopupMenu;
                }

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set popup_menu is not implemented"));
                }

                break;

            case "instant":
                if (constant.IsTruthy())
                {
                    _proc.Attributes |= ProcAttributes.Instant;
                }
                else
                {
                    _proc.Attributes &= ~ProcAttributes.Instant;
                }

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set instant is not implemented"));
                }
                break;

            case "background":
                if (constant.IsTruthy())
                {
                    _proc.Attributes |= ProcAttributes.Background;
                }
                else
                {
                    _proc.Attributes &= ~ProcAttributes.Background;
                }

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set background is not implemented"));
                }
                break;

            case "name":
                DMASTConstantString name = statementSet.Value as DMASTConstantString;
                if (name is null)
                {
                    throw new CompileErrorException(statementSet.Location, "bad text");
                }
                _proc.VerbName = name.Value;

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set name is not implemented"));
                }

                break;

            case "category":
                DMASTConstantString category = statementSet.Value as DMASTConstantString;
                if (category is null)
                {
                    throw new CompileErrorException(statementSet.Location, "bad text");
                }
                _proc.VerbCategory = category.Value;

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set category is not implemented"));
                }
                break;

            case "desc":
                DMASTConstantString desc = statementSet.Value as DMASTConstantString;
                if (desc is null)
                {
                    throw new CompileErrorException(statementSet.Location, "bad text");
                }
                _proc.VerbDesc = desc.Value;

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set desc is not implemented"));
                }
                break;

            case "invisibility":
                // The ref says 0-101 for atoms and 0-100 for verbs
                // BYOND doesn't clamp the actual var value but it does seem to treat out-of-range values as their extreme
                DMASTConstantFloat invisFloat = statementSet.Value as DMASTConstantFloat;
                if (invisFloat is null)
                {
                    DMASTConstantInteger invisInt = statementSet.Value as DMASTConstantInteger;
                    if (invisInt is null)
                    {
                        throw new CompileErrorException(statementSet.Location, "bad num");
                    }
                    _proc.Invisibility = Convert.ToSByte(Math.Clamp(invisInt.Value, 0, 100));
                }
                else
                {
                    _proc.Invisibility = Convert.ToSByte(Math.Clamp(Math.Floor(invisFloat.Value), 0, 100));
                }

                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set invisibility is not implemented"));
                }
                break;

            case "src":
                if (!DMCompiler.Settings.SuppressUnimplementedWarnings)
                {
                    DMCompiler.Warning(new CompilerWarning(statementSet.Location, "set src is not implemented"));
                }
                break;
            }
        }