Skip to content

Commit

Permalink
Major refactoring and basic variable creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Toxic-Cookie committed Dec 29, 2021
1 parent ed1894a commit 1afe4b3
Show file tree
Hide file tree
Showing 12 changed files with 739 additions and 318 deletions.
191 changes: 191 additions & 0 deletions Core/ExperimentalSyntaxWalker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using BaseX;
using FrooxEngine;
using FrooxEngine.LogiX;
using System.Reflection;

namespace SharpLogix.Core
{
/// <summary>
/// A hellscape of generics.
/// </summary>
class ExperimentalSyntaxWalker : CSharpSyntaxWalker
{
public static readonly List<Type> LogixNodeTypes = new List<Type>();

int RecursionLevel;
int CurrentNamespace = -1;
int CurrentScript = -1;
readonly Slot SpawnRoot;
readonly List<SharpLogixScript> sharpLogixScripts = new List<SharpLogixScript>();

readonly SemanticModel semanticModel;

static ExperimentalSyntaxWalker()
{
foreach (Type AvailableType in AppDomain.CurrentDomain.GetAssemblies().
SelectMany(assemblies => assemblies.GetTypes()).
Where(currentType => currentType.IsSubclassOf(typeof(LogixNode))))
{
LogixNodeTypes.Add(AvailableType);
}
}

public ExperimentalSyntaxWalker(Slot spawnRoot, string Name, SemanticModel model)
{
semanticModel = model;
SpawnRoot = spawnRoot.AddSlot(Name);
}

public override void Visit(SyntaxNode node)
{
//string indents = new string('\t', Tabs);
//Core.Debug.Log(indents + node.Kind());
RecursionLevel++;
base.Visit(node);
RecursionLevel--;
}

//Assume one namespace for now.
/*
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
{
CurrentNamespace++;
node.Name.ToString();
base.VisitNamespaceDeclaration(node);
}
*/

public override void VisitClassDeclaration(ClassDeclarationSyntax node)
{
//Class information. Eg myClass.
sharpLogixScripts.Add(new SharpLogixScript(SpawnRoot));
CurrentScript++;

string identifier = node.Identifier.ValueText;

sharpLogixScripts[CurrentScript].Root.Name = identifier;
sharpLogixScripts[CurrentScript].Root.AttachComponent<DynamicVariableSpace>().SpaceName.Value = identifier;

base.VisitClassDeclaration(node);
}

public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
{
base.VisitFieldDeclaration(node);
}
public override void VisitVariableDeclaration(VariableDeclarationSyntax node)
{
foreach (VariableDeclaratorSyntax variable in node.Variables)
{
Slot VariableSlot = sharpLogixScripts[CurrentScript].Members.AddSlot(string.Concat(node.Type.ToString(), " ", variable.Identifier.ValueText));
Type VariableType = Type.GetType(GetFullMetadataName(semanticModel.GetSymbolInfo(node.Type).Symbol));

object Initializer = null;

if (variable.Initializer != null)
{
Initializer = Convert.ChangeType(variable.Initializer.ChildNodes().First().ToString(), VariableType);
}

Type[] dynVarType = new Type[1] { VariableType };
if (VariableType.IsClass && typeof(IWorldElement).IsAssignableFrom(VariableType))
{
MethodInfo method = GetType().GetMethod(nameof(AddDRV), BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Slot), typeof(string), typeof(object) }, null);
MethodInfo generic = method.MakeGenericMethod(dynVarType);
object[] parameters = new object[3] { VariableSlot, variable.Identifier.ValueText, Initializer };
generic.Invoke(this, parameters);
}
else
{
MethodInfo method = GetType().GetMethod(nameof(AddDVV), BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Slot), typeof(string), typeof(object) }, null);
MethodInfo generic = method.MakeGenericMethod(dynVarType);
object[] parameters = new object[3] { VariableSlot, variable.Identifier.ValueText, Initializer };
generic.Invoke(this, parameters);
}
}

base.VisitVariableDeclaration(node);
}
void AddDRV<T>(Slot slot, string name, object value) where T : class, IWorldElement
{
var drv = slot.AttachComponent<DynamicReferenceVariable<T>>();
drv.VariableName.Value = name;

if (value != null)
{
drv.DynamicValue = (T)value;
}
}
void AddDVV<T>(Slot slot, string name, object value)
{
var drv = slot.AttachComponent<DynamicValueVariable<T>>();
drv.VariableName.Value = name;

if (value != null)
{
drv.DynamicValue = (T)value;
}
}

//Magic
static string GetFullMetadataName(ISymbol s)
{
if (s == null || IsRootNamespace(s))
{
return string.Empty;
}

var sb = new StringBuilder(s.MetadataName);
var last = s;

s = s.ContainingSymbol;

while (!IsRootNamespace(s))
{
if (s is ITypeSymbol && last is ITypeSymbol)
{
sb.Insert(0, '+');
}
else
{
sb.Insert(0, '.');
}

sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
//sb.Insert(0, s.MetadataName);
s = s.ContainingSymbol;
}

return sb.ToString();
}
static bool IsRootNamespace(ISymbol symbol)
{
INamespaceSymbol s = null;
return ((s = symbol as INamespaceSymbol) != null) && s.IsGlobalNamespace;
}

public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
sharpLogixScripts[CurrentScript].Methods.AddSlot(string.Concat(node.ReturnType.ToString(), " ", node.Identifier.ValueText, "()"));

base.VisitMethodDeclaration(node);
}
}
}
15 changes: 15 additions & 0 deletions Core/LogixBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SharpLogix.Core
{
/// <summary>
/// The class responsible for constructing the actual node graphs.
/// </summary>
class LogixBuilder
{
}
}
59 changes: 59 additions & 0 deletions Core/SharpLogixCompiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using NeosModLoader;
using HarmonyLib;
using BaseX;
using FrooxEngine;

namespace SharpLogix.Core
{
class SharpLogixCompiler : NeosMod
{
public override string Name => "SharpLogix";
//Originally forked from: https://github.com/vr-voyage/SharpLogix and refactored into a nml mod.
public override string Author => "Toxic_Cookie";
public override string Version => "1.0.0";
public override string Link => "https://github.com/Toxic-Cookie/SharpLogix";
public override void OnEngineInit()
{
Core.Debug.Log("Hello World!");

Harmony harmony = new Harmony("net.Toxic_Cookie.SharpLogix");
harmony.PatchAll();
}

[HarmonyPatch(typeof(ImageImportDialog), "OnAttach")]
class ImportScript
{
public static void Postfix()
{
string MyProgram = @"
namespace MyProgram
{
class Class1
{
int TestIntA;
int TestIntB = 3;
int TestIntC;
void Start()
{
TestIntA = 2;
TestIntC = TestIntA + TestIntB;
}
}
}
";

new SharpLogixProgram(MyProgram, "Hello World");
}
}
}
}
39 changes: 39 additions & 0 deletions Core/SharpLogixProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using BaseX;
using FrooxEngine;

namespace SharpLogix.Core
{
class SharpLogixProgram
{
public SharpLogixProgram(string Program, string Name = "Unnamed Program", Slot spawnRoot = null)
{
if (spawnRoot == null)
{
spawnRoot = Engine.Current.WorldManager.FocusedWorld.RootSlot;
}
//slx = SharpLogix
if (!Name.EndsWith(".slx"))
{
Name = string.Concat(Name, ".slx");
}

SyntaxTree tree = CSharpSyntaxTree.ParseText(Program);

//Might require end user to reference their libs. A given but oof.
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var compilation = CSharpCompilation.Create("slxCompilation", syntaxTrees: new[] { tree }, references: new[] { mscorlib });

ExperimentalSyntaxWalker walker = new ExperimentalSyntaxWalker(spawnRoot, Name, compilation.GetSemanticModel(tree));
walker.Visit(tree.GetRoot());
}
}
}
35 changes: 35 additions & 0 deletions Core/SharpLogixScript.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using BaseX;
using FrooxEngine;
using FrooxEngine.LogiX;

namespace SharpLogix.Core
{
/// <summary>
/// A Neos representation of a class.
/// </summary>
class SharpLogixScript
{
public readonly Slot SpawnSlot;
public readonly Slot Root;
public readonly Slot Assembly;
public readonly Slot Members;
public readonly Slot Methods;
public readonly Slot Debug;

public SharpLogixScript(Slot spawnRoot, string Name = "Unnamed Script")
{
SpawnSlot = spawnRoot;
Root = SpawnSlot.AddSlot(Name);
Assembly = Root.AddSlot("Assembly");
Members = Assembly.AddSlot("Members");
Methods = Assembly.AddSlot("Methods");
Debug = Assembly.AddSlot("Debug");
}
}
}
File renamed without changes
23 changes: 23 additions & 0 deletions Media/Parsing Rules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

################
PARSING RULES:
################

Variables
=========
Local Variables: Represented as Value / Reference Registers.
Global Variables: Represented as Dynamic Variables.
Literals: Represented as input nodes.

Methods
=======
Methods will be called via impulses.

Program Flow
============
if, for, while, etc will be interpreted literally.
?:, ??, etc will be drive based.

Component Access
================
Only members setup to be accessible at compile time will be accessible.
Loading

0 comments on commit 1afe4b3

Please sign in to comment.