public void ProcessVarDefinition(DMASTObjectVarDefinition varDefinition) { DMObject oldObject = _currentObject; DMVariable variable; _currentObject = DMObjectTree.GetDMObject(varDefinition.ObjectPath); if (varDefinition.IsGlobal) { variable = _currentObject.CreateGlobalVariable(varDefinition.Type, varDefinition.Name, varDefinition.IsConst); } else { variable = new DMVariable(varDefinition.Type, varDefinition.Name, false, varDefinition.IsConst); _currentObject.Variables[variable.Name] = variable; } try { SetVariableValue(variable, varDefinition.Value, varDefinition.ValType); } catch (CompileErrorException e) { DMCompiler.Error(e.Error); } _currentObject = oldObject; }
public void ProcessVarOverride(DMASTObjectVarOverride varOverride) { DMObject oldObject = _currentObject; _currentObject = DMObjectTree.GetDMObject(varOverride.ObjectPath); try { if (varOverride.VarName == "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); } else { DMVariable variable = new DMVariable(null, varOverride.VarName, false, false); SetVariableValue(variable, varOverride.Value); _currentObject.VariableOverrides[variable.Name] = variable; } } catch (CompileErrorException e) { DMCompiler.Error(e.Error); } _currentObject = oldObject; }
private void SetVariableValue(DMVariable variable, DMASTExpression value, DMValueType valType = DMValueType.Anything) { DMVisitorExpression._scopeMode = variable.IsGlobal ? "static" : "normal"; DMExpression expression = DMExpression.Create(_currentObject, variable.IsGlobal ? DMObjectTree.GlobalInitProc : null, value, variable.Type); DMVisitorExpression._scopeMode = "normal"; expression.ValType = valType; if (expression.TryAsConstant(out var constant)) { variable.Value = constant; return; } if (variable.IsConst) { throw new CompileErrorException(value.Location, "Value of const var must be a constant"); } //Whether this should be initialized at runtime bool isValid = expression switch { //TODO: A better way of handling procs evaluated at compile time Expressions.ProcCall procCall => procCall.GetTargetProc(_currentObject).Proc?.Name switch { "rgb" => true, "generator" => true, "matrix" => true, "icon" => true, "file" => true, "sound" => true, _ => variable.IsGlobal },
private static void 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)) { throw new Exception($"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.WhenWritingNull }); File.WriteAllText(outputFile, json); Console.WriteLine("Saved to " + outputFile); }
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; var jsonRep = DMObjectTree.CreateJsonRepresentation(); compiledDream.Types = jsonRep.Item1; compiledDream.Procs = jsonRep.Item2; 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 = DMObjectTree.GlobalProcs.Values.ToList(); } 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); }
public override bool TryAsConstant(out Constant constant) { DMVariable global = DMObjectTree.Globals[Id]; if (global.IsConst) { return(global.Value.TryAsConstant(out constant)); } constant = null; return(false); }
private void SetVariableValue(DMVariable variable, DMASTExpression value, DMValueType valType = DMValueType.Anything) { DMVisitorExpression._scopeMode = variable.IsGlobal ? "static" : "normal"; DMExpression expression = DMExpression.Create(_currentObject, variable.IsGlobal ? DMObjectTree.GlobalInitProc : null, value, variable.Type); DMVisitorExpression._scopeMode = "normal"; expression.ValType = valType; if (expression.TryAsConstant(out var constant)) { variable.Value = constant; return; } if (variable.IsConst) { throw new CompileErrorException(value.Location, "Value of const var must be a constant"); } switch (expression) { case Expressions.List: case Expressions.NewList: case Expressions.NewPath: //TODO: A better way of handling procs evaluated at compile time case Expressions.ProcCall procCall when procCall.GetTargetProc(_currentObject).Proc?.Name == "rgb": variable.Value = new Expressions.Null(Location.Unknown); EmitInitializationAssign(variable, expression); break; case Expressions.ProcCall procCall when procCall.GetTargetProc(_currentObject).Proc?.Name == "generator": variable.Value = new Expressions.Null(Location.Unknown); EmitInitializationAssign(variable, expression); break; case Expressions.StringFormat: case Expressions.ProcCall: if (!variable.IsGlobal) { throw new CompileErrorException(value.Location, $"Invalid initial value for \"{variable.Name}\""); } variable.Value = new Expressions.Null(Location.Unknown); EmitInitializationAssign(variable, expression); break; default: throw new CompileErrorException(value.Location, $"Invalid initial value for \"{variable.Name}\""); } }
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); } }
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; }
public Field(Location location, DMVariable variable) : base(location, variable.Type) { Variable = variable; }
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); } }