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(); }
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); } }
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(); }
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); }
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(); }
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 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); }
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}\""); } } }
public void ProcessFile(DMASTFile file) { _currentObject = DMObjectTree.GetDMObject(DreamPath.Root); ProcessBlockInner(file.BlockInner); }
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); } }
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); }