Beispiel #1
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 #2
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 #3
0
        public void BuildObjectTree(DMASTFile astFile)
        {
            DMObjectTree.Reset();
            ProcessFile(astFile);

            // TODO Nuke this pass
            foreach (DMObject dmObject in DMObjectTree.AllObjects)
            {
                dmObject.CreateInitializationProc();
            }

            foreach (DMProc proc in DMObjectTree.AllProcs)
            {
                proc.Compile();
            }

            DMObjectTree.CreateGlobalInitProc();
        }
Beispiel #4
0
        public void VisitUpwardPathSearch(DMASTUpwardPathSearch constant)
        {
            DMExpression.TryConstant(_dmObject, _proc, constant.Path, out var pathExpr);
            if (pathExpr is not Expressions.Path)
            {
                throw new CompileErrorException(constant.Location, "Cannot do an upward path search on " + pathExpr);
            }

            DreamPath path      = ((Expressions.Path)pathExpr).Value;
            DreamPath?foundPath = DMObjectTree.UpwardSearch(path, constant.Search.Path);

            if (foundPath == null)
            {
                throw new CompileErrorException(constant.Location, $"Invalid path {path}.{constant.Search.Path}");
            }

            Result = new Expressions.Path(constant.Location, foundPath.Value);
        }
Beispiel #5
0
        public void BuildObjectTree(DMASTFile astFile)
        {
            DMObjectTree.Reset();
            ProcessFile(astFile);

            foreach (DMObject dmObject in DMObjectTree.AllObjects)
            {
                dmObject.CompileProcs();
            }

            DMObject root = DMObjectTree.GetDMObject(DreamPath.Root);

            foreach (DMProc gProc in DMObjectTree.GlobalProcs.Values)
            {
                gProc.Compile(root);
            }

            DMObjectTree.CreateGlobalInitProc();
        }
Beispiel #6
0
        private void EmitInitializationAssign(DMVariable variable, DMExpression expression)
        {
            if (variable.IsGlobal)
            {
                int?globalId = _currentObject.GetGlobalVariableId(variable.Name);
                if (globalId == null)
                {
                    throw new Exception($"Invalid global {_currentObject.Path}.{variable.Name}");
                }

                DMObjectTree.AddGlobalInitAssign(_currentObject, globalId.Value, expression);
            }
            else
            {
                Expressions.Field      field  = new Expressions.Field(Location.Unknown, variable);
                Expressions.Assignment assign = new Expressions.Assignment(Location.Unknown, field, expression);

                _currentObject.InitializationProcExpressions.Add(assign);
            }
        }
Beispiel #7
0
        public void ProcessVarOverride(DMASTObjectVarOverride varOverride)
        {
            DMObject oldObject = _currentObject;

            _currentObject = DMObjectTree.GetDMObject(varOverride.ObjectPath);

            try
            {
                switch (varOverride.VarName)
                {
                case "parent_type":
                {
                    DMASTConstantPath parentType = varOverride.Value as DMASTConstantPath;

                    if (parentType == null)
                    {
                        throw new CompileErrorException(varOverride.Location, "Expected a constant path");
                    }
                    _currentObject.Parent = DMObjectTree.GetDMObject(parentType.Value.Path);
                    break;
                }

                case "tag":
                    DMCompiler.Error(new CompilerError(varOverride.Location, "tag: may not be set at compile-time"));
                    break;

                default:
                {
                    DMVariable variable = new DMVariable(null, varOverride.VarName, false, false);

                    SetVariableValue(variable, varOverride.Value);
                    _currentObject.VariableOverrides[variable.Name] = variable;
                    break;
                }
                }
            } catch (CompileErrorException e) {
                DMCompiler.Error(e.Error);
            }

            _currentObject = oldObject;
        }
Beispiel #8
0
        public override bool TryAsJsonRepresentation(out object json)
        {
            object value;

            if (DMObjectTree.TryGetTypeId(Value, out int typeId))
            {
                value = typeId;
            }
            else
            {
                value = Value.PathString;
            }

            json = new Dictionary <string, object>()
            {
                { "type", JsonVariableType.Path },
                { "value", value }
            };

            return(true);
        }
Beispiel #9
0
 public void VisitCallableProcIdentifier(DMASTCallableProcIdentifier procIdentifier)
 {
     if (_scopeMode == "static")
     {
         Result = new Expressions.GlobalProc(procIdentifier.Location, procIdentifier.Identifier);
     }
     else
     {
         if (_dmObject.HasProc(procIdentifier.Identifier))
         {
             Result = new Expressions.Proc(procIdentifier.Location, procIdentifier.Identifier);
         }
         else if (DMObjectTree.TryGetGlobalProc(procIdentifier.Identifier, out _))
         {
             Result = new Expressions.GlobalProc(procIdentifier.Location, procIdentifier.Identifier);
         }
         else
         {
             throw new CompileErrorException(procIdentifier.Location, $"Type {_dmObject.Path} does not have a proc named \"{procIdentifier.Identifier}\"");
         }
     }
 }
Beispiel #10
0
        public void ProcessFile(DMASTFile file)
        {
            _currentObject = DMObjectTree.GetDMObject(DreamPath.Root);

            ProcessBlockInner(file.BlockInner);
        }
Beispiel #11
0
        public void ProcessProcDefinition(DMASTProcDefinition procDefinition)
        {
            string   procName = procDefinition.Name;
            DMObject dmObject = _currentObject;

            try {
                if (procDefinition.ObjectPath.HasValue)
                {
                    dmObject = DMObjectTree.GetDMObject(_currentObject.Path.Combine(procDefinition.ObjectPath.Value));
                }

                if (!procDefinition.IsOverride && dmObject.HasProc(procName))
                {
                    throw new CompileErrorException(procDefinition.Location, $"Type {dmObject.Path} already has a proc named \"{procName}\"");
                }

                DMProc proc;

                if (procDefinition.ObjectPath == null)
                {
                    if (DMObjectTree.TryGetGlobalProc(procDefinition.Name, out _))
                    {
                        throw new CompileErrorException(new CompilerError(procDefinition.Location, $"proc {procDefinition.Name} is already defined in global scope"));
                    }

                    proc = DMObjectTree.CreateDMProc(dmObject, procDefinition);
                    DMObjectTree.AddGlobalProc(proc.Name, proc.Id);
                }
                else
                {
                    proc = DMObjectTree.CreateDMProc(dmObject, procDefinition);
                    dmObject.AddProc(procName, proc);
                }

                if (procDefinition.Body != null)
                {
                    foreach (var stmt in GetStatements(procDefinition.Body))
                    {
                        // TODO multiple var definitions.
                        if (stmt is DMASTProcStatementVarDeclaration varDeclaration && varDeclaration.IsGlobal)
                        {
                            DMVariable variable = proc.CreateGlobalVariable(varDeclaration.Type, varDeclaration.Name, varDeclaration.IsConst);
                            variable.Value = new Expressions.Null(varDeclaration.Location);

                            if (varDeclaration.Value != null)
                            {
                                DMVisitorExpression._scopeMode = "static";
                                DMExpression expression = DMExpression.Create(dmObject, proc, varDeclaration.Value, varDeclaration.Type);
                                DMVisitorExpression._scopeMode = "normal";
                                DMObjectTree.AddGlobalInitAssign(dmObject, proc.GetGlobalVariableId(varDeclaration.Name).Value, expression);
                            }
                        }
                    }
                }

                if (procDefinition.IsVerb && (dmObject.IsSubtypeOf(DreamPath.Atom) || dmObject.IsSubtypeOf(DreamPath.Client)) && !DMCompiler.Settings.NoStandard)
                {
                    Expressions.Field  field    = new Expressions.Field(Location.Unknown, dmObject.GetVariable("verbs"));
                    DreamPath          procPath = new DreamPath(".proc/" + procName);
                    Expressions.Append append   = new Expressions.Append(Location.Unknown, field, new Expressions.Path(Location.Unknown, procPath));

                    dmObject.InitializationProcExpressions.Add(append);
                }
            } catch (CompileErrorException e) {
                DMCompiler.Error(e.Error);
            }
        }
Beispiel #12
0
        private static string SaveJson(List <DreamMapJson> maps, string interfaceFile, string outputFile)
        {
            DreamCompiledJson compiledDream = new DreamCompiledJson();

            compiledDream.Strings   = DMObjectTree.StringTable;
            compiledDream.Maps      = maps;
            compiledDream.Interface = interfaceFile;
            compiledDream.Types     = DMObjectTree.CreateJsonRepresentation();
            if (DMObjectTree.GlobalInitProc.Bytecode.Length > 0)
            {
                compiledDream.GlobalInitProc = DMObjectTree.GlobalInitProc.GetJsonRepresentation();
            }

            if (DMObjectTree.Globals.Count > 0)
            {
                GlobalListJson globalListJson = new GlobalListJson();
                globalListJson.GlobalCount = DMObjectTree.Globals.Count;

                // Approximate capacity (4/285 in tgstation, ~3%)
                globalListJson.Globals = new Dictionary <int, object>((int)(DMObjectTree.Globals.Count * 0.03));

                for (int i = 0; i < DMObjectTree.Globals.Count; i++)
                {
                    DMVariable global = DMObjectTree.Globals[i];
                    if (!global.TryAsJsonRepresentation(out var globalJson))
                    {
                        DMCompiler.Error(new CompilerError(global.Value.Location, $"Failed to serialize global {global.Name}"));
                    }

                    if (globalJson != null)
                    {
                        globalListJson.Globals.Add(i, globalJson);
                    }
                }
                compiledDream.Globals = globalListJson;
            }

            if (DMObjectTree.GlobalProcs.Count > 0)
            {
                compiledDream.GlobalProcs = new(DMObjectTree.GlobalProcs.Count);

                foreach (KeyValuePair <string, DMProc> globalProc in DMObjectTree.GlobalProcs)
                {
                    string name = globalProc.Key;
                    DMProc proc = globalProc.Value;

                    compiledDream.GlobalProcs[name] = proc.GetJsonRepresentation();
                }
            }

            string json = JsonSerializer.Serialize(compiledDream, new JsonSerializerOptions()
            {
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
            });

            // Successful serialization
            if (ErrorCount == 0)
            {
                File.WriteAllText(outputFile, json);
                return("Saved to " + outputFile);
            }
            return(string.Empty);
        }