Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
run: chmod -R +x ./src/NodeDev.Blazor.Server/bin

- name: Ensure browsers are installed
run: pwsh ./src/NodeDev.EndToEndTests/bin/Debug/net8.0/playwright.ps1 install --with-deps
run: pwsh ./src/NodeDev.EndToEndTests/bin/Debug/net9.0/playwright.ps1 install --with-deps

- name: Test
env:
Expand Down
2 changes: 1 addition & 1 deletion src/NodeDev.Blazor.Server/NodeDev.Blazor.Server.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/NodeDev.Blazor/Components/SourceViewer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ else

try
{
Creator = Method.Graph.Project.CreateNodeClassTypeCreator(new(Core.Nodes.BuildExpressionOptions.Release, true));
Creator = Method.Graph.Project.CreateNodeClassTypeCreator(Core.BuildOptions.Debug with { PreBuildOnly = true });
Creator.CreateProjectClassesAndAssembly();

try
Expand Down
6 changes: 6 additions & 0 deletions src/NodeDev.Blazor/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<MudAppBar Elevation="1" data-test-id="appBar">
<MudButton OnClick="NewProject" Class="ml-3" data-test-id="newProject">New Project</MudButton>
<MudButton OnClick="Save" Class="ml-3" data-test-id="Save">Save</MudButton>
<MudButton OnClick="Build" Class="ml-3" data-test-id="Build">Build</MudButton>
<MudButton OnClick="Add" Class="ml-3">Add node</MudButton>
<MudButton OnClick="Run" Class="ml-3">Run</MudButton>
<MudButton OnClick="SwitchLiveDebugging">@(Project.IsLiveDebuggingEnabled ? "Stop Live Debugging" : "Start Live Debugging")</MudButton>
Expand Down Expand Up @@ -185,6 +186,11 @@
//GraphCanvas?.ShowAddNode();
}

public void Build()
{
Project.Build(Project.IsLiveDebuggingEnabled ? Core.BuildOptions.Debug : Core.BuildOptions.Release);
}

public void Run()
{
new Thread(() =>
Expand Down
5 changes: 2 additions & 3 deletions src/NodeDev.Blazor/NodeDev.Blazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand All @@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="BlazorMonaco" Version="3.2.0" />
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="7.0.0-rc.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0-rc.1.24452.1" />
<PackageReference Include="MudBlazor" Version="7.2.0" />
</ItemGroup>

Expand All @@ -26,5 +26,4 @@
<None Include="wwwroot\styles.css" />
</ItemGroup>


</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public void DisconnectConnectionBetween(Connection source, Connection destinatio
/// <param name="initiatingConnection">The connection that initiated the propagation. This is used to avoid reupdating back and forth, sometimes erasing information in the process.</param>
public void PropagateNewGeneric(Node node, IReadOnlyDictionary<string, TypeBase> changedGenerics, bool useInitialTypes, Connection? initiatingConnection, bool overrideInitialTypes)
{
node.OnBeforeGenericTypeDefined(changedGenerics);

bool hadAnyChanges = false;
foreach (var port in node.InputsAndOutputs) // check if any of the ports have the generic we just solved
{
Expand Down
6 changes: 3 additions & 3 deletions src/NodeDev.Core/BuildOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace NodeDev.Core;

public record class BuildOptions(BuildExpressionOptions BuildExpressionOptions, bool PreBuildOnly)
public record class BuildOptions(BuildExpressionOptions BuildExpressionOptions, bool PreBuildOnly, string OutputPath)
{
public static readonly BuildOptions Debug = new(BuildExpressionOptions.Debug, false);
public static readonly BuildOptions Debug = new(BuildExpressionOptions.Debug, false, "bin/Debug");

public static readonly BuildOptions Release = new(BuildExpressionOptions.Release, false);
public static readonly BuildOptions Release = new(BuildExpressionOptions.Release, false, "bin/Release");
}
31 changes: 22 additions & 9 deletions src/NodeDev.Core/Class/NodeClassTypeCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public record class GeneratedType(Type Type, TypeBuilder HiddenType, Dictionary<
public static string HiddenName(string name) => $"_hidden_{name}";
private static GeneratedType CreateGeneratedType(ModuleBuilder mb, string name) => new(mb.DefineType(name, TypeAttributes.Public | TypeAttributes.Class), mb.DefineType(HiddenName(name), TypeAttributes.NotPublic | TypeAttributes.Class | TypeAttributes.Sealed), []);

public Assembly? Assembly { get; private set; }
public AssemblyBuilder? Assembly { get; private set; }

public readonly Project Project;

Expand All @@ -31,14 +31,28 @@ internal NodeClassTypeCreator(Project project, BuildOptions buildOptions)
Options = buildOptions;
}

private static Assembly TemporaryReflectionAssembly;
public void CreateProjectClassesAndAssembly()
{
// https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.assemblybuilder?view=net-7.0
var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("NodeProject_" + this.Project.Id.ToString().Replace('-', '_')), AssemblyBuilderAccess.RunAndCollect);
Assembly = ab;

// The module name is usually the same as the assembly name.
var mb = ab.DefineDynamicModule(ab.GetName().Name!);
{
// TODO Remove this when the new System.Reflection.Emit is available in .NET 10
if (TemporaryReflectionAssembly == null)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("NodeDev.Core.Dependencies.System.Reflection.Emit.dll")!;
var bytes = new byte[stream.Length];
stream.ReadExactly(bytes);
TemporaryReflectionAssembly = System.Reflection.Assembly.Load(bytes);
}
var persisted = Activator.CreateInstance(TemporaryReflectionAssembly.ExportedTypes.First(), new AssemblyName("NodeProject_" + this.Project.Id.ToString().Replace('-', '_')), typeof(object).Assembly, null)!;
Assembly = (AssemblyBuilder)persisted;


// https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.assemblybuilder?view=net-7.0
//var persisted = new PersistedAssemblyBuilder(new AssemblyName("NodeProject_" + this.Project.Id.ToString().Replace('-', '_')), typeof(object).Assembly);
//Assembly = persisted;

// The module name is usually the same as the assembly name.
var mb = Assembly.DefineDynamicModule(Assembly.GetName().Name!);

// Creating all the types early so they are all accessible during expression tree generation
foreach (var nodeClass in Project.Classes)
Expand All @@ -48,7 +62,6 @@ public void CreateProjectClassesAndAssembly()
generatedType = GeneratedTypes[Project.GetNodeClassType(nodeClass)];
else
GeneratedTypes[Project.GetNodeClassType(nodeClass)] = generatedType = CreateGeneratedType(mb, nodeClass.Name);

}

// Create the properties and methods in the real type
Expand Down
Binary file not shown.
9 changes: 7 additions & 2 deletions src/NodeDev.Core/NodeDev.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.1</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FastExpressionCompiler" Version="4.2.1" />
<PackageReference Include="NuGet.Versioning" Version="6.10.1" />
<PackageReference Include="NuGet.Versioning" Version="6.11.0" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Dis2Msil\Dis2Msil\Dis2Msil.csproj" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Dependencies\System.Reflection.Emit.dll">
</EmbeddedResource>
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions src/NodeDev.Core/Nodes/ArrayGet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ public ArrayGet(Graph graph, string? id = null) : base(graph, id)
Outputs.Add(new("Obj", this, undefinedT));
}

internal override Expression BuildExpression(Dictionary<Connection, Graph.NodePathChunks>? subChunks, BuildExpressionInfo info)
internal override void BuildInlineExpression(BuildExpressionInfo info)
{
if (!Inputs[0].Type.IsArray)
throw new Exception("ArrayGet.Inputs[0] should be an array type");

var arrayIndex = Expression.ArrayIndex(info.LocalVariables[Inputs[0]], info.LocalVariables[Inputs[1]]);
return Expression.Assign(info.LocalVariables[Outputs[1]], arrayIndex);
info.LocalVariables[Outputs[0]] = arrayIndex;
}
}
21 changes: 21 additions & 0 deletions src/NodeDev.Core/Nodes/Cast.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using NodeDev.Core.Types;
using System.Linq.Expressions;

namespace NodeDev.Core.Nodes;

public class Cast : NoFlowNode
{
public Cast(Graph graph, string? id = null) : base(graph, id)
{
Inputs.Add(new("Value", this, new UndefinedGenericType("T1")));

Outputs.Add(new("Result", this, new UndefinedGenericType("T2")));
}

public override string Name => "Cast";

internal override void BuildInlineExpression(BuildExpressionInfo info)
{
info.LocalVariables[Outputs[0]] = Expression.Convert(info.LocalVariables[Inputs[0]], Outputs[0].Type.MakeRealType());
}
}
2 changes: 1 addition & 1 deletion src/NodeDev.Core/Nodes/Debug/WriteLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ internal override Expression BuildExpression(Dictionary<Connection, Graph.NodePa
if (method == null)
throw new Exception("Unable to find Console.WriteLine method");

return Expression.Call(null, method, info.LocalVariables[Inputs[1]]);
return Expression.Call(null, method, Expression.Convert(info.LocalVariables[Inputs[1]], typeof(object)));
}
}
9 changes: 7 additions & 2 deletions src/NodeDev.Core/Nodes/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,13 @@ public Node(Graph graph, string? id = null)
/// </summary>
public int GraphIndex { get; set; } = -1;

public IEnumerable<string> GetUndefinedGenericTypes() => InputsAndOutputs.SelectMany(x => x.Type.GetUndefinedGenericTypes()).Distinct();
public virtual IEnumerable<string> GetUndefinedGenericTypes() => InputsAndOutputs.SelectMany(x => x.Type.GetUndefinedGenericTypes()).Distinct();

/// <summary>
/// Called before the generic type are set on every connections
/// </summary>
public virtual void OnBeforeGenericTypeDefined(IReadOnlyDictionary<string, TypeBase> changedGenerics) {}


public record class AlternateOverload(TypeBase ReturnType, List<IMethodParameterInfo> Parameters);
public virtual IEnumerable<AlternateOverload> AlternatesOverloads => [];
Expand Down Expand Up @@ -292,7 +298,6 @@ protected virtual void Deserialize(SerializedNode serializedNodeObj)
}
}


#endregion
}
}
76 changes: 76 additions & 0 deletions src/NodeDev.Core/Nodes/TypeOf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using NodeDev.Core.NodeDecorations;
using NodeDev.Core.Types;
using System.Linq.Expressions;

namespace NodeDev.Core.Nodes;

/// <summary>
/// Returns the selected type. Represent C# '<see langword="typeof"/>' keyword.
/// </summary>
public class TypeOf : NoFlowNode
{
private class CurrentUndefinedType : INodeDecoration
{
public TypeBase Type { get; }

public CurrentUndefinedType(TypeBase undefinedType)
{
Type = undefinedType;
}

public string Serialize()
{
return Type.SerializeWithFullTypeNameString();
}

public static INodeDecoration Deserialize(TypeFactory typeFactory, string json)
{
return new CurrentUndefinedType(TypeBase.DeserializeFullTypeNameString(typeFactory, json));
}
}

public TypeOf(Graph graph, string? id = null) : base(graph, id)
{
Outputs.Add(new("Type", this, TypeFactory.Get<Type>()));

Type = new UndefinedGenericType("T");
Decorations.Add(typeof(CurrentUndefinedType), new CurrentUndefinedType(Type));
}

private TypeBase Type;

public override string Name => "TypeOf";

public override IEnumerable<string> GetUndefinedGenericTypes()
{
if (Type is UndefinedGenericType undefined)
return [undefined.Name];

return [];
}

public override void OnBeforeGenericTypeDefined(IReadOnlyDictionary<string, TypeBase> changedGenerics)
{
if(Type is not UndefinedGenericType undefined)
return;

if (changedGenerics.TryGetValue(undefined.Name, out var newType))
{
Type = newType;
Decorations[typeof(CurrentUndefinedType)] = new CurrentUndefinedType(Type);
}
}

protected override void Deserialize(SerializedNode serializedNodeObj)
{
base.Deserialize(serializedNodeObj);

Type = ((CurrentUndefinedType)(Decorations[typeof(CurrentUndefinedType)])).Type;
}

internal override void BuildInlineExpression(BuildExpressionInfo info)
{
info.LocalVariables[Outputs[0]] = Expression.Constant(Type.MakeRealType());
}

}
Loading
Loading