Skip to content

Commit

Permalink
Add support for new /proc/new_verb(Destination)
Browse files Browse the repository at this point in the history
  • Loading branch information
wixoaGit committed Feb 12, 2024
1 parent c8e10e0 commit 0ff2e96
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 72 deletions.
4 changes: 2 additions & 2 deletions DMCompiler/Compiler/DM/DMAST.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1769,10 +1769,10 @@ public override void Visit(DMASTVisitor visitor) {
}

public sealed class DMASTNewPath : DMASTExpression {
public readonly DMASTPath Path;
public readonly DMASTConstantPath Path;
public readonly DMASTCallParameter[] Parameters;

public DMASTNewPath(Location location, DMASTPath path, DMASTCallParameter[] parameters) : base(location) {
public DMASTNewPath(Location location, DMASTConstantPath path, DMASTCallParameter[] parameters) : base(location) {
Path = path;
Parameters = parameters;
}
Expand Down
2 changes: 1 addition & 1 deletion DMCompiler/Compiler/DM/DMParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2082,7 +2082,7 @@ public void ExpressionTo(out DMASTExpression? endRange, out DMASTExpression? ste
DMASTCallParameter[]? parameters = ProcCall();

DMASTExpression? newExpression = type switch {
DMASTConstantPath path => new DMASTNewPath(loc, path.Value, parameters),
DMASTConstantPath path => new DMASTNewPath(loc, path, parameters),
DMASTExpression expr => new DMASTNewExpr(loc, expr, parameters),
null => new DMASTNewInferred(loc, parameters),
};
Expand Down
34 changes: 19 additions & 15 deletions DMCompiler/DM/Expressions/Builtins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,33 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}

// new /x/y/z (...)
sealed class NewPath : DMExpression {
private readonly DreamPath _targetPath;
private readonly ArgumentList _arguments;

public NewPath(Location location, DreamPath targetPath, ArgumentList arguments) : base(location) {
_targetPath = targetPath;
_arguments = arguments;
}
internal sealed class NewPath(Location location, Path targetPath, ArgumentList arguments) : DMExpression(location) {
public override DreamPath? Path => targetPath.Value;

public override void EmitPushValue(DMObject dmObject, DMProc proc) {
if (!DMObjectTree.TryGetTypeId(_targetPath, out var typeId)) {
DMCompiler.Emit(WarningCode.ItemDoesntExist, Location, $"Type {_targetPath} does not exist");

if (!targetPath.TryResolvePath(out var pathInfo)) {
proc.PushNull();
return;
}

var argumentInfo = _arguments.EmitArguments(dmObject, proc);
var argumentInfo = arguments.EmitArguments(dmObject, proc);

switch (pathInfo.Value.Type) {
case Expressions.Path.PathType.TypeReference:
proc.PushType(pathInfo.Value.Id);
break;
case Expressions.Path.PathType.ProcReference: // "new /proc/new_verb(Destination)" is a thing
proc.PushProc(pathInfo.Value.Id);
break;
case Expressions.Path.PathType.ProcStub:
case Expressions.Path.PathType.VerbStub:
DMCompiler.Emit(WarningCode.BadExpression, Location, "Cannot use \"new\" with a proc stub");
proc.PushNull();
return;
}

proc.PushType(typeId);
proc.CreateObject(argumentInfo.Type, argumentInfo.StackSize);
}

public override DreamPath? Path => _targetPath;
}

// locate()
Expand Down
15 changes: 5 additions & 10 deletions DMCompiler/DM/Expressions/Constant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,26 +477,21 @@ public override bool TryAsJsonRepresentation(out object? json) {
}

// /a/b/c
sealed class Path : Constant {
public DreamPath Value { get; }
internal sealed class Path(Location location, DMObject dmObject, DreamPath value) : Constant(location) {
public DreamPath Value { get; } = value;

/// <summary>
/// The DMObject this expression resides in. Used for path searches.
/// </summary>
private readonly DMObject _dmObject;
private readonly DMObject _dmObject = dmObject;

private enum PathType {
public enum PathType {
TypeReference,
ProcReference,
ProcStub,
VerbStub
}

public Path(Location location, DMObject dmObject, DreamPath value) : base(location) {
Value = value;
_dmObject = dmObject;
}

public override void EmitPushValue(DMObject dmObject, DMProc proc) {
if (!TryResolvePath(out var pathInfo)) {
proc.PushNull();
Expand Down Expand Up @@ -554,7 +549,7 @@ public override bool TryAsJsonRepresentation(out object? json) {
return true;
}

private bool TryResolvePath([NotNullWhen(true)] out (PathType Type, int Id)? pathInfo) {
public bool TryResolvePath([NotNullWhen(true)] out (PathType Type, int Id)? pathInfo) {
DreamPath path = Value;

// An upward search with no left-hand side
Expand Down
18 changes: 12 additions & 6 deletions DMCompiler/DM/Visitors/DMExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,18 +193,24 @@ public static DMExpression BuildExpression(DMASTExpression expression, DMObject
BuildExpression(ternary.B, dmObject, proc, inferredPath),
BuildExpression(ternary.C ?? new DMASTConstantNull(ternary.Location), dmObject, proc, inferredPath));
case DMASTNewPath newPath:
return new NewPath(newPath.Location,
newPath.Path.Path,
if (BuildExpression(newPath.Path, dmObject, proc, inferredPath) is not Path path) {
DMCompiler.Emit(WarningCode.BadExpression, newPath.Path.Location, "Expected a path expression");
return new Null(newPath.Location);
}

return new NewPath(newPath.Location, path,
new ArgumentList(newPath.Location, dmObject, proc, newPath.Parameters, inferredPath));
case DMASTNewExpr newExpr:
return new New(newExpr.Location,
BuildExpression(newExpr.Expression, dmObject, proc, inferredPath),
new ArgumentList(newExpr.Location, dmObject, proc, newExpr.Parameters, inferredPath));
case DMASTNewInferred newInferred:
if (inferredPath is null)
throw new CompileErrorException(newInferred.Location, "An inferred new requires a type!");
return new NewPath(newInferred.Location,
inferredPath.Value,
if (inferredPath is null) {
DMCompiler.Emit(WarningCode.BadExpression, newInferred.Location, "Could not infer a type");
return new Null(newInferred.Location);
}

return new NewPath(newInferred.Location, new Path(newInferred.Location, dmObject, inferredPath.Value),
new ArgumentList(newInferred.Location, dmObject, proc, newInferred.Parameters, inferredPath));
case DMASTPreIncrement preIncrement:
return new PreIncrement(preIncrement.Location, BuildExpression(preIncrement.Expression, dmObject, proc, inferredPath));
Expand Down
4 changes: 2 additions & 2 deletions OpenDreamRuntime/Objects/DreamObjectTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void LoadJson(DreamCompiledJson json) {
Strings = json.Strings ?? new();

if (json.GlobalInitProc is { } initProcDef) {
GlobalInitProc = new DMProc(0, Root, initProcDef, "<global init>", _dreamManager, _atomManager, _dreamMapManager, _dreamDebugManager, _dreamResourceManager, this, _procScheduler);
GlobalInitProc = new DMProc(0, Root, initProcDef, "<global init>", _dreamManager, _atomManager, _dreamMapManager, _dreamDebugManager, _dreamResourceManager, this, _procScheduler, _verbSystem);
} else {
GlobalInitProc = null;
}
Expand Down Expand Up @@ -400,7 +400,7 @@ private void LoadVariablesFromJson(DreamObjectDefinition objectDefinition, Dream
public DreamProc LoadProcJson(int id, ProcDefinitionJson procDefinition) {
TreeEntry owningType = Types[procDefinition.OwningTypeId];
return new DMProc(id, owningType, procDefinition, null, _dreamManager,
_atomManager, _dreamMapManager, _dreamDebugManager, _dreamResourceManager, this, _procScheduler);
_atomManager, _dreamMapManager, _dreamDebugManager, _dreamResourceManager, this, _procScheduler, _verbSystem);
}

private void LoadProcsFromJson(ProcDefinitionJson[]? jsonProcs, int[]? jsonGlobalProcs) {
Expand Down
37 changes: 25 additions & 12 deletions OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,37 +170,50 @@ public static ProcStatus CreateObject(DMProcState state) {
if (!state.Proc.ObjectTree.TryGetTreeEntry(pathString, out objectType)) {
ThrowCannotCreateUnknownObject(val);
}
} else if (val.TryGetValueAsProc(out var proc)) { // new /proc/proc_name(Destination,Name,Desc)
var arguments = state.PopProcArguments(null, argumentInfo.Type, argumentInfo.StackSize);
var destination = arguments.GetArgument(0);

// TODO: Name and Desc arguments

if (destination.TryGetValueAsDreamObject<DreamObjectAtom>(out var atom)) {
state.Proc.AtomManager.UpdateAppearance(atom, appearance => {
state.Proc.VerbSystem.RegisterVerb(proc);

appearance.Verbs.Add(proc.VerbId!.Value);
});
} else if (destination.TryGetValueAsDreamObject<DreamObjectClient>(out var client)) {
client.ClientVerbs.AddValue(val);
}

return ProcStatus.Continue;
} else {
ThrowCannotCreateObjectFromInvalid(val);
}
}

var objectDef = objectType.ObjectDefinition;
var proc = objectDef.GetProc("New");
var arguments = state.PopProcArguments(proc, argumentInfo.Type, argumentInfo.StackSize);
var newProc = objectDef.GetProc("New");
var newArguments = state.PopProcArguments(newProc, argumentInfo.Type, argumentInfo.StackSize);

if (objectDef.IsSubtypeOf(state.Proc.ObjectTree.Turf)) {
// Turfs are special. They're never created outside of map initialization
// So instead this will replace an existing turf's type and return that same turf
DreamValue loc = arguments.GetArgument(0);
DreamValue loc = newArguments.GetArgument(0);
if (!loc.TryGetValueAsDreamObject<DreamObjectTurf>(out var turf))
ThrowInvalidTurfLoc(loc);

state.Proc.DreamMapManager.SetTurf(turf, objectDef, arguments);
state.Proc.DreamMapManager.SetTurf(turf, objectDef, newArguments);

state.Push(loc);
return ProcStatus.Continue;
}

DreamObject newObject = state.Proc.ObjectTree.CreateObject(objectType);
var s = newObject.InitProc(state.Thread, state.Usr, arguments);
if (s is not null) {
state.Thread.PushProcState(s);
return ProcStatus.Called;
}
var newObject = state.Proc.ObjectTree.CreateObject(objectType);
var s = newObject.InitProc(state.Thread, state.Usr, newArguments);

state.Push(new DreamValue(newObject));
return ProcStatus.Continue;
state.Thread.PushProcState(s);
return ProcStatus.Called;
}

[MethodImpl(MethodImplOptions.NoInlining)]
Expand Down
6 changes: 4 additions & 2 deletions OpenDreamRuntime/Procs/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ public sealed class DMProc : DreamProc {
public readonly IDreamDebugManager DreamDebugManager;
public readonly DreamResourceManager DreamResourceManager;
public readonly DreamObjectTree ObjectTree;
public readonly ServerVerbSystem VerbSystem;

private readonly int _maxStackSize;

public DMProc(int id, TreeEntry owningType, ProcDefinitionJson json, string? name, DreamManager dreamManager, AtomManager atomManager, IDreamMapManager dreamMapManager, IDreamDebugManager dreamDebugManager, DreamResourceManager dreamResourceManager, DreamObjectTree objectTree, ProcScheduler procScheduler)
public DMProc(int id, TreeEntry owningType, ProcDefinitionJson json, string? name, DreamManager dreamManager, AtomManager atomManager, IDreamMapManager dreamMapManager, IDreamDebugManager dreamDebugManager, DreamResourceManager dreamResourceManager, DreamObjectTree objectTree, ProcScheduler procScheduler, ServerVerbSystem verbSystem)
: base(id, owningType, name ?? json.Name, null, json.Attributes, GetArgumentNames(json), GetArgumentTypes(json), json.VerbSrc, json.VerbName, json.VerbCategory, json.VerbDesc, json.Invisibility, json.IsVerb) {
Bytecode = json.Bytecode ?? Array.Empty<byte>();
LocalNames = json.Locals;
Expand All @@ -39,11 +40,12 @@ public DMProc(int id, TreeEntry owningType, ProcDefinitionJson json, string? nam

AtomManager = atomManager;
DreamManager = dreamManager;
ProcScheduler = procScheduler;
DreamMapManager = dreamMapManager;
DreamDebugManager = dreamDebugManager;
DreamResourceManager = dreamResourceManager;
ObjectTree = objectTree;
ProcScheduler = procScheduler;
VerbSystem = verbSystem;
}

public (string Source, int Line) GetSourceAtOffset(int offset) {
Expand Down
44 changes: 22 additions & 22 deletions OpenDreamRuntime/Procs/DreamProcArguments.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
using System.Runtime.CompilerServices;

namespace OpenDreamRuntime.Procs {
public readonly ref struct DreamProcArguments {
public int Count => Values.Length;
namespace OpenDreamRuntime.Procs;

public readonly ReadOnlySpan<DreamValue> Values;
public readonly ref struct DreamProcArguments {
public int Count => Values.Length;

public DreamProcArguments() {
Values = Array.Empty<DreamValue>();
}
public readonly ReadOnlySpan<DreamValue> Values;

public DreamProcArguments(ReadOnlySpan<DreamValue> values) {
Values = values;
}
public DreamProcArguments() {
Values = Array.Empty<DreamValue>();
}

public DreamProcArguments(params DreamValue[] values) {
Values = values;
}
public DreamProcArguments(ReadOnlySpan<DreamValue> values) {
Values = values;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public DreamValue GetArgument(int argumentPosition) {
if (Count > argumentPosition) {
return Values[argumentPosition];
}
public DreamProcArguments(params DreamValue[] values) {
Values = values;
}

return DreamValue.Null;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public DreamValue GetArgument(int argumentPosition) {
if (Count > argumentPosition) {
return Values[argumentPosition];
}

public override string ToString() {
return $"<Arguments {Count}>";
}
return DreamValue.Null;
}

public override string ToString() {
return $"<Arguments {Count}>";
}
}

0 comments on commit 0ff2e96

Please sign in to comment.