port from perforce
This commit is contained in:
14
intromat/Intromat/Nodes/Code/BooleanLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/BooleanLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("BooleanLiteral", Namespace = _namespace)]
|
||||
public sealed class BooleanLiteralModel : LiteralModelBase<bool>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new BooleanLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/BooleanLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/BooleanLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class BooleanLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static BooleanLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<BooleanLiteralNode>));
|
||||
}
|
||||
|
||||
public BooleanLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Boolean";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<bool>>(EPortType.Boolean)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new BooleanLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "False");
|
||||
}
|
||||
|
||||
public BooleanValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<bool>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new BooleanLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var booleanLiteral = (BooleanLiteralModel)model;
|
||||
ValueEditor.Value = booleanLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var booleanLiteral = (BooleanLiteralModel)model;
|
||||
booleanLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
intromat/Intromat/Nodes/Code/BooleanLiteralValue.cs
Normal file
6
intromat/Intromat/Nodes/Code/BooleanLiteralValue.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class BooleanLiteralValue : LiteralValueBase<bool>
|
||||
{
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/FloatLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/FloatLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("FloatLiteral", Namespace = _namespace)]
|
||||
public sealed class FloatLiteralModel : LiteralModelBase<float>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new FloatLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/FloatLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/FloatLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FloatLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static FloatLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<FloatLiteralNode>));
|
||||
}
|
||||
|
||||
public FloatLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Float";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new FloatLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "0.0");
|
||||
}
|
||||
|
||||
public FloatValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<float>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new FloatLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var floatLiteral = (FloatLiteralModel)model;
|
||||
ValueEditor.Value = floatLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var floatLiteral = (FloatLiteralModel)model;
|
||||
floatLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
intromat/Intromat/Nodes/Code/FloatLiteralValue.cs
Normal file
9
intromat/Intromat/Nodes/Code/FloatLiteralValue.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FloatLiteralValue : LiteralValueBase<float>
|
||||
{
|
||||
public override string? PreviewValue => Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
19
intromat/Intromat/Nodes/Code/ForLoopModel.cs
Normal file
19
intromat/Intromat/Nodes/Code/ForLoopModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("ForLoop", Namespace = _namespace)]
|
||||
public sealed class ForLoopModel : NodeModelBase
|
||||
{
|
||||
public IntLiteralModel FirstIndex { get; set; } = null!;
|
||||
|
||||
public IntLiteralModel LastIndex { get; set; } = null!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new ForLoopNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
intromat/Intromat/Nodes/Code/ForLoopNode.cs
Normal file
114
intromat/Intromat/Nodes/Code/ForLoopNode.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class ForLoopNode : ExecutionNodeBase
|
||||
{
|
||||
static ForLoopNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<ForLoopNode>));
|
||||
}
|
||||
|
||||
public ForLoopNode() : base(NodeType.Code)
|
||||
{
|
||||
var boundsGroup = new EndpointGroup("Bounds");
|
||||
|
||||
Name = "For Loop";
|
||||
|
||||
LoopBodyFlow = new CodeGenInputViewModel<IStatement>(EPortType.Execution)
|
||||
{
|
||||
Name = "Loop Body",
|
||||
Group = _executionFlowGroup
|
||||
};
|
||||
Inputs.Add(LoopBodyFlow);
|
||||
|
||||
FirstIndex = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "First Index",
|
||||
Group = boundsGroup,
|
||||
Editor = FirstIndexEditor
|
||||
};
|
||||
Inputs.Add(FirstIndex);
|
||||
|
||||
LastIndex = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Last Index",
|
||||
Group = boundsGroup,
|
||||
Editor = LastIndexEditor
|
||||
};
|
||||
|
||||
Inputs.Add(LastIndex);
|
||||
|
||||
var loopBodyChanged = LoopBodyFlow.ValueChanged.Select(_ => Unit.Default).StartWith(Unit.Default);
|
||||
FlowIn.Value = loopBodyChanged
|
||||
.CombineLatest(FlowOutChanged, FirstIndex.ValueChanged, LastIndex.ValueChanged, (bodyChange, endChange, firstI, lastI) => (BodyChange: bodyChange, EndChange: endChange, FirstI: firstI, LastI: lastI))
|
||||
.Select(v => new ForLoopValue
|
||||
{
|
||||
LoopBody = LoopBodyFlow.Value,
|
||||
FlowOut = FlowOut.Value,
|
||||
LowerBound = v.FirstI,
|
||||
UpperBound = v.LastI
|
||||
});
|
||||
|
||||
CurrentIndex = new CodeGenOutputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Current Index",
|
||||
Value = FlowIn.Value.Select(v => new VariableReference<int> { LocalVariable = ((ForLoopValue)v).CurrentIndex })
|
||||
};
|
||||
Outputs.Add(CurrentIndex);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
FlowIn.Value.Subscribe(v =>
|
||||
{
|
||||
var forLoop = (ForLoopValue)v;
|
||||
stringPreview.Value = $"[{forLoop.LowerBound?.PreviewValue ?? "0"}..{forLoop.UpperBound?.PreviewValue ?? "0"}]";
|
||||
});
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<IStatement> LoopBodyFlow { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel FirstIndexEditor { get; } = new();
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> FirstIndex { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel LastIndexEditor { get; } = new();
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> LastIndex { get; }
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<int>> CurrentIndex { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new ForLoopModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var forLoop = (ForLoopModel)model;
|
||||
forLoop.FirstIndex = FirstIndexEditor.CreateModel();
|
||||
forLoop.LastIndex = LastIndexEditor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var forLoop = (ForLoopModel)model;
|
||||
FirstIndexEditor.LoadModel(forLoop.FirstIndex);
|
||||
LastIndexEditor.LoadModel(forLoop.LastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
intromat/Intromat/Nodes/Code/ForLoopValue.cs
Normal file
48
intromat/Intromat/Nodes/Code/ForLoopValue.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class ForLoopValue : ExecutionValueBase
|
||||
{
|
||||
public IStatement? LoopBody { get; set; }
|
||||
|
||||
public ITypedExpression<int>? LowerBound { get; set; }
|
||||
public ITypedExpression<int>? UpperBound { get; set; }
|
||||
|
||||
public InlineVariableDefinition<int> CurrentIndex { get; } = new();
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
Debug.Assert(UpperBound != null, nameof(UpperBound) + " != null");
|
||||
|
||||
context.EnterNewScope("For loop");
|
||||
|
||||
CurrentIndex.Value = LowerBound;
|
||||
sb.Append("for (");
|
||||
CurrentIndex.Compile(context, sb);
|
||||
sb.Append("; ");
|
||||
sb.Append(CurrentIndex.VariableName);
|
||||
sb.Append(" <= ");
|
||||
UpperBound.Compile(context, sb);
|
||||
sb.Append("; ++");
|
||||
sb.Append(CurrentIndex.VariableName);
|
||||
sb.Append(")\n{\n");
|
||||
LoopBody?.Compile(context, sb);
|
||||
sb.Append("\n}\n");
|
||||
|
||||
context.LeaveScope();
|
||||
|
||||
base.Compile(context, sb);
|
||||
}
|
||||
|
||||
public override void CompileHeader(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
LoopBody?.CompileHeader(context, sb);
|
||||
|
||||
base.CompileHeader(context, sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
intromat/Intromat/Nodes/Code/FunctionCall.cs
Normal file
31
intromat/Intromat/Nodes/Code/FunctionCall.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FunctionCall : ExecutionValueBase
|
||||
{
|
||||
public string? FunctionName { get; set; }
|
||||
public List<IExpression> Parameters { get; } = new();
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
Debug.Assert(FunctionName != null, nameof(FunctionName) + " != null");
|
||||
|
||||
sb.Append($"{FunctionName}(");
|
||||
for (int i = 0, n = Parameters.Count; i < n; ++i)
|
||||
{
|
||||
var p = Parameters[i];
|
||||
p.Compile(context, sb);
|
||||
if (i != n - 1)
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(")\n");
|
||||
|
||||
base.Compile(context, sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/IntLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/IntLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("IntLiteral", Namespace = _namespace)]
|
||||
public sealed class IntLiteralModel : LiteralModelBase<int>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new IntLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/IntLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/IntLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class IntLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static IntLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<IntLiteralNode>));
|
||||
}
|
||||
|
||||
public IntLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Integer";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new IntLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "0");
|
||||
}
|
||||
|
||||
public IntegerValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<int>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new IntLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var intLiteral = (IntLiteralModel)model;
|
||||
ValueEditor.Value = intLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var intLiteral = (IntLiteralModel)model;
|
||||
intLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
intromat/Intromat/Nodes/Code/IntLiteralValue.cs
Normal file
25
intromat/Intromat/Nodes/Code/IntLiteralValue.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class IntLiteralValue : LiteralValueBase<int>
|
||||
{
|
||||
public int EvaluateDimension()
|
||||
{
|
||||
var relativeDimension = RelativeSource switch
|
||||
{
|
||||
ERelativeSource.Parent => 1 << ParentValue,
|
||||
ERelativeSource.Input => InputValue,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
var result = Value switch
|
||||
{
|
||||
< 0 => relativeDimension >> -Value,
|
||||
> 0 => relativeDimension << Value,
|
||||
_ => relativeDimension
|
||||
};
|
||||
return Math.Max(1, Math.Min(8192, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
34
intromat/Intromat/Nodes/Code/LiteralModelBase.cs
Normal file
34
intromat/Intromat/Nodes/Code/LiteralModelBase.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Textures;
|
||||
using Intromat.PersistentModel;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public enum ERelativeSource
|
||||
{
|
||||
Custom,
|
||||
Parent,
|
||||
Input
|
||||
}
|
||||
|
||||
[XmlInclude(typeof(IntLiteralModel))]
|
||||
[XmlInclude(typeof(StringLiteralModel))]
|
||||
[XmlInclude(typeof(FloatLiteralModel))]
|
||||
[XmlInclude(typeof(BooleanLiteralModel))]
|
||||
[XmlInclude(typeof(SamplerLiteralModel))]
|
||||
public abstract class LiteralModelBase : NodeModelBase
|
||||
{
|
||||
public ERelativeSource RelativeSource { get; set; }
|
||||
}
|
||||
|
||||
public class LiteralModelEntry
|
||||
{
|
||||
public string Key { get; set; } = null!;
|
||||
public LiteralModelBase Literal { get; set; } = null!;
|
||||
}
|
||||
|
||||
public abstract class LiteralModelBase<T> : LiteralModelBase
|
||||
{
|
||||
public T Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
28
intromat/Intromat/Nodes/Code/LiteralValueBase.cs
Normal file
28
intromat/Intromat/Nodes/Code/LiteralValueBase.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public abstract class LiteralValueBase<T> : ITypedExpression<T>
|
||||
{
|
||||
public virtual string? PreviewValue => Value?.ToString();
|
||||
|
||||
public T ParentValue { get; set; } = default!;
|
||||
|
||||
public T InputValue { get; set; } = default!;
|
||||
|
||||
public T Value { get; set; } = default!;
|
||||
|
||||
public ERelativeSource RelativeSource { get; set; }
|
||||
|
||||
public virtual void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
sb.Append(Value);
|
||||
}
|
||||
|
||||
public virtual T Evaluate()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
intromat/Intromat/Nodes/Code/PrintModel.cs
Normal file
17
intromat/Intromat/Nodes/Code/PrintModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("Print", Namespace = _namespace)]
|
||||
public sealed class PrintModel : NodeModelBase
|
||||
{
|
||||
public string? Text { get; set; }
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new PrintNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
intromat/Intromat/Nodes/Code/PrintNode.cs
Normal file
75
intromat/Intromat/Nodes/Code/PrintNode.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class PrintNode : ExecutionNodeBase
|
||||
{
|
||||
static PrintNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<PrintNode>));
|
||||
}
|
||||
|
||||
public PrintNode() : base(NodeType.Code)
|
||||
{
|
||||
Name = "Print";
|
||||
|
||||
Text = new CodeGenInputViewModel<ITypedExpression<string>>(EPortType.String)
|
||||
{
|
||||
Name = "Text",
|
||||
Editor = TextEditor
|
||||
};
|
||||
Inputs.Add(Text);
|
||||
|
||||
FlowIn.Value = FlowOutChanged
|
||||
.CombineLatest(Text.ValueChanged, (flowOutChanged, textValueChanged) => (FlowOutChanged: flowOutChanged, StringExpression: textValueChanged))
|
||||
.Select(v => new FunctionCall
|
||||
{
|
||||
FunctionName = "print",
|
||||
FlowOut = FlowOut.Value,
|
||||
Parameters = { v.StringExpression ?? new StringLiteralValue { Value = "" } }
|
||||
});
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Text.Value)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Text.Value.PreviewValue ?? string.Empty);
|
||||
}
|
||||
|
||||
public StringExpressionEditorViewModel TextEditor { get; } = new();
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<string>> Text { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new PrintModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var print = (PrintModel)model;
|
||||
print.Text = TextEditor.Value is StringLiteralValue text ? text.Value : null;
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var print = (PrintModel)model;
|
||||
if (print.Text != null)
|
||||
TextEditor.Value = new StringLiteralValue { Value = print.Text };
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/StringFileModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/StringFileModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("StringFile", Namespace = _namespace)]
|
||||
public sealed class StringFileModel : LiteralModelBase<string?>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new StringFileNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
intromat/Intromat/Nodes/Code/StringFileNode.cs
Normal file
121
intromat/Intromat/Nodes/Code/StringFileNode.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.Utilities;
|
||||
using ReactiveUI;
|
||||
using RxFileSystemWatcher;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringFileNode : CodeGenNodeViewModel
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<ObservableFileSystemWatcher> _fileWatcher;
|
||||
private readonly ObservableAsPropertyHelper<string> _fullPath;
|
||||
|
||||
static StringFileNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<StringFileNode>));
|
||||
}
|
||||
|
||||
public StringFileNode()
|
||||
: base(NodeType.Literal)
|
||||
{
|
||||
Name = "String (file)";
|
||||
|
||||
Path = new CodeGenInputViewModel<string?>(EPortType.String)
|
||||
{
|
||||
Name = "Path",
|
||||
Editor = PathEditor,
|
||||
};
|
||||
Inputs.Add(Path);
|
||||
|
||||
Contents = new CodeGenOutputViewModel<ITypedExpression<string?>>(EPortType.String)
|
||||
{
|
||||
Name = "Contents",
|
||||
};
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Parent, vm => vm.Path.Value)
|
||||
.Where(pair => pair.Item1 != null && pair.Item2 != null)
|
||||
.Select(pair => System.IO.Path.Combine(((CodeGenNetworkViewModel)pair.Item1).Document.Parent.FullPath, pair.Item2!))
|
||||
.StartWith(string.Empty)
|
||||
.ToProperty(this, vm => vm.FullPath, out _fullPath);
|
||||
|
||||
this.WhenAnyValue(vm => vm.FullPath)
|
||||
.Where(File.Exists)
|
||||
.Select(path => new ObservableFileSystemWatcher(c =>
|
||||
{
|
||||
c.Path = System.IO.Path.GetDirectoryName(path)!;
|
||||
}))
|
||||
.ToProperty(this, vm => vm.FileWatcher, out _fileWatcher);
|
||||
|
||||
Contents.Value = this.WhenAnyValue(vm => vm.FileWatcher)
|
||||
.PairWithPreviousValue()
|
||||
.Select(pair =>
|
||||
{
|
||||
var oldWatcher = pair.OldValue;
|
||||
var newWatcher = pair.NewValue;
|
||||
|
||||
oldWatcher?.Dispose();
|
||||
if (newWatcher != null)
|
||||
{
|
||||
stringPreview.Value = Path.Value!;
|
||||
var result =
|
||||
newWatcher.Renamed.Where(e => e.FullPath == FullPath)
|
||||
.Merge(newWatcher.Changed.Where(e => e.FullPath == FullPath))
|
||||
.Throttle(TimeSpan.FromMilliseconds(100))
|
||||
.Select(_ => new StringLiteralValue() { Value = File.ReadAllText(FullPath) })
|
||||
.StartWith(new StringLiteralValue() { Value = File.ReadAllText(FullPath) });
|
||||
newWatcher.Start();
|
||||
return result;
|
||||
}
|
||||
|
||||
stringPreview.Value = string.Empty;
|
||||
return Observable.Empty<StringLiteralValue>();
|
||||
})
|
||||
.Switch();
|
||||
|
||||
Outputs.Add(Contents);
|
||||
}
|
||||
|
||||
public ObservableFileSystemWatcher FileWatcher => _fileWatcher.Value;
|
||||
|
||||
public string FullPath => _fullPath.Value;
|
||||
|
||||
public StringValueEditorViewModel PathEditor { get; } = new();
|
||||
|
||||
public ValueNodeInputViewModel<string?> Path { get; }
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<string?>> Contents { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new StringFileModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var fileModel = (StringFileModel)model;
|
||||
PathEditor.Value = fileModel.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var fileModel = (StringFileModel)model;
|
||||
fileModel.Value = PathEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/StringLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/StringLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("StringLiteral", Namespace = _namespace)]
|
||||
public sealed class StringLiteralModel : LiteralModelBase<string?>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new StringLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/StringLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/StringLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static StringLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<StringLiteralNode>));
|
||||
}
|
||||
|
||||
public StringLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "String";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<string?>>(EPortType.String)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new StringLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = ((StringLiteralValue)Output.CurrentValue).Value ?? string.Empty);
|
||||
}
|
||||
|
||||
public StringValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<string?>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new StringLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var textLiteral = (StringLiteralModel)model;
|
||||
ValueEditor.Value = textLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var textLiteral = (StringLiteralModel)model;
|
||||
textLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
intromat/Intromat/Nodes/Code/StringLiteralValue.cs
Normal file
21
intromat/Intromat/Nodes/Code/StringLiteralValue.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringLiteralValue : LiteralValueBase<string?>
|
||||
{
|
||||
public override string? PreviewValue => Value;
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
sb.Append($"\"{Value}\"");
|
||||
}
|
||||
|
||||
public override string Evaluate()
|
||||
{
|
||||
return Value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Nodes/Code/VariableReference.cs
Normal file
32
intromat/Intromat/Nodes/Code/VariableReference.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.Model.Compiler.Error;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class VariableReference<T> : ITypedExpression<T>
|
||||
{
|
||||
public string? PreviewValue => LocalVariable?.VariableName;
|
||||
|
||||
public ITypedVariableDefinition<T>? LocalVariable { get; set; }
|
||||
|
||||
public void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
var localVariable = LocalVariable;
|
||||
Debug.Assert(localVariable != null, nameof(localVariable) + " != null");
|
||||
Debug.Assert(localVariable.VariableName != null, $"{nameof(localVariable)}.{nameof(localVariable.VariableName)} != null");
|
||||
|
||||
if (!context.IsInScope(localVariable))
|
||||
throw new VariableOutOfScopeException(localVariable.VariableName);
|
||||
|
||||
sb.Append(localVariable.VariableName);
|
||||
}
|
||||
public T Evaluate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user