diff --git a/Icons/UIRule.svg b/Icons/UIRule.svg
new file mode 100644
index 0000000..2572058
--- /dev/null
+++ b/Icons/UIRule.svg
@@ -0,0 +1,201 @@
+
+
diff --git a/Icons/UIRule.svg.import b/Icons/UIRule.svg.import
new file mode 100644
index 0000000..bb3a487
--- /dev/null
+++ b/Icons/UIRule.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b53un3tjulppj"
+path="res://.godot/imported/UIRule.svg-dd35f8a9b19c4e01c4e95c28eb989981.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/UIRule.svg"
+dest_files=["res://.godot/imported/UIRule.svg-dd35f8a9b19c4e01c4e95c28eb989981.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Icons/UIRuleSet.svg b/Icons/UIRuleSet.svg
new file mode 100644
index 0000000..b12124d
--- /dev/null
+++ b/Icons/UIRuleSet.svg
@@ -0,0 +1,414 @@
+
+
diff --git a/Icons/UIRuleSet.svg.import b/Icons/UIRuleSet.svg.import
new file mode 100644
index 0000000..1e1afc7
--- /dev/null
+++ b/Icons/UIRuleSet.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bqo22c1m73dyu"
+path="res://.godot/imported/UIRuleSet.svg-421bda2d7476eddcafe1e07da9c0badf.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/UIRuleSet.svg"
+dest_files=["res://.godot/imported/UIRuleSet.svg-421bda2d7476eddcafe1e07da9c0badf.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Icons/UISelector.svg b/Icons/UISelector.svg
new file mode 100644
index 0000000..bb08e74
--- /dev/null
+++ b/Icons/UISelector.svg
@@ -0,0 +1,110 @@
+
+
diff --git a/Icons/UISelector.svg.import b/Icons/UISelector.svg.import
new file mode 100644
index 0000000..91d2b89
--- /dev/null
+++ b/Icons/UISelector.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://6rml2liif4ns"
+path="res://.godot/imported/UISelector.svg-1da3b1c2f5d0e50773a94b5a365f6476.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/UISelector.svg"
+dest_files=["res://.godot/imported/UISelector.svg-1da3b1c2f5d0e50773a94b5a365f6476.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Runtime/Actions/Action.cs b/Runtime/Actions/Action.cs
index 676a827..56d1fb8 100644
--- a/Runtime/Actions/Action.cs
+++ b/Runtime/Actions/Action.cs
@@ -3,208 +3,225 @@ using Godot;
using System.Collections.Generic;
-namespace Rokojori
-{
- [Tool]
- [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")]
- public partial class Action : NetworkNode
+namespace Rokojori;
+
+[Tool]
+[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")]
+public partial class Action : NetworkNode
+{
+ public enum ActionTriggerMode
{
- public enum ActionTriggerMode
+ Only_When_Processing_In_Hierarchy,
+ Always
+ }
+
+ [Export]
+ public ActionTriggerMode triggerMode = ActionTriggerMode.Always;
+
+ #if !GD_SCRIPT_TRANSPILING
+
+ [ExportToolButton( "(?) Help", Icon = "Help") ]
+ public Callable openHelpButton => Callable.From( ()=>
+ {
+ #if TOOLS
+ Rokojori.Tools.OnlineDocs.Open( GetType() );
+ #endif
+ }
+ );
+
+ #endif
+
+ [ExportToolButton( "Trigger Action in Editor")]
+ public Callable TriggerActionButton => Callable.From( ()=> Trigger() );
+
+ #if !GD_SCRIPT_TRANSPILING
+
+ public static bool IsAction( Node n )
+ {
+ if ( n == null )
{
- Only_When_Processing_In_Hierarchy,
- Always
+ return false;
}
- [Export]
- public ActionTriggerMode triggerMode = ActionTriggerMode.Only_When_Processing_In_Hierarchy;
-
- [ExportToolButton( "(?) Help", Icon = "Help") ]
- public Callable openHelpButton => Callable.From( ()=>
- {
- #if TOOLS
- Rokojori.Tools.OnlineDocs.Open( GetType() );
- #endif
- }
- );
-
- [ExportToolButton( "Trigger Action in Editor")]
- public Callable TriggerActionButton => Callable.From( ()=> Trigger() );
-
- NetworkNodeSlot _seedSlot = new NetworkNodeSlot();
- NetworkNodeSlot _dataSlot = new NetworkNodeSlot();
- NetworkNodeSlot _seedAndDataSlot = new NetworkNodeSlot();
-
- public static bool IsAction( Node n )
- {
- if ( n == null )
- {
- return false;
- }
-
- return n is Action || GDScriptAction.IsRJAction( n );
- }
-
- public void LogInfoFor( Node n, string message )
- {
- var className = GDScriptNames.ExtractClassName( n );
- RJLog.GDLog( $"{className}._onTrigger()", n, message );
- }
-
-
- protected override List CreateNetworkNodeMembers()
- {
- return new List()
- {
- _networkNodeSlot,
- _seedSlot,
- _dataSlot,
- _seedAndDataSlot
- };
- }
-
- public Action()
- {
-
- }
-
- public void Trigger()
- {
- if ( ! IsInstanceValid( this ) )
- {
- return;
- }
-
- if ( triggerMode == ActionTriggerMode.Only_When_Processing_In_Hierarchy && ! this.IsProcessingInHierarchy() )
- {
- return;
- }
-
- _isNetworkedTrigger = false;
- _sendsSeed = false;
- _sendsData = false;
- _OnTrigger();
-
- SendOverNetwork();
-
- }
-
- protected void SendOverNetwork()
- {
- // check which type
- // 0 0 => vanilla
- // 1 0 => with seed
- // 0 1 => with data
- // 1 1 => with seed + data
- }
-
- protected void _OnNetworkTrigger( int seed, BitView data )
- {
- _isNetworkedTrigger = true;
- _receivedNetworkSeed = seed;
- _receivedNetworkData = data;
-
- _OnTrigger();
-
- _isNetworkedTrigger = false;
- }
-
- bool _isNetworkedTrigger = false;
- int _receivedNetworkSeed = -1;
- int _sendingNetworkSeed = -1;
-
- bool _sendsSeed = false;
- bool _sendsData = false;
-
- BitView _sendingNetworkData;
- BitView _receivedNetworkData;
-
- public bool isNetworkedTrigger => _isNetworkedTrigger;
-
- static readonly int maxNetworkSeed = Mathf.RoundToInt( Mathf.Pow( 2, 30 ) );
-
- protected int networkSeed
- {
- get
- {
- if ( _isNetworkedTrigger )
- {
- return _receivedNetworkSeed;
- }
-
- if ( _sendsSeed )
- {
- return _sendingNetworkSeed;
- }
-
- _sendingNetworkSeed = GodotRandom.Get().IntegerExclusive( 0, maxNetworkSeed );
- _sendsSeed = true;
-
- return _sendingNetworkSeed;
- }
- }
-
- protected BitView GetNetworkData( BitView view )
- {
- if ( _isNetworkedTrigger )
- {
- return _receivedNetworkData;
- }
-
- _sendingNetworkData = view;
- _sendsData = true;
- return _sendingNetworkData;
- }
-
- protected virtual void _OnTrigger()
- {
-
- }
+ return n is Action || GDScriptAction.IsRJAction( n );
+ }
- public static void Trigger( Action action )
+ public void LogInfoFor( Node n, string message )
+ {
+ var className = GDScriptNames.ExtractClassName( n );
+ RJLog.GDLog( $"{className}._onTrigger()", n, message );
+ }
+
+ #endif
+
+ public void Trigger()
+ {
+ if ( ! IsInstanceValid( this ) )
{
- if ( action == null )
- {
- return;
- }
-
- action.Trigger();
+ return;
}
- public static void TriggerAll( Action[] actions, Node target, bool triggerDirectChildren, Action caller = null )
+ if ( triggerMode == ActionTriggerMode.Only_When_Processing_In_Hierarchy && ! this.IsProcessingInHierarchy() )
{
- if ( actions != null )
- {
- for ( int i = 0; i < actions.Length; i++ )
- {
- Action.Trigger( actions[ i ] );
- }
- }
-
- if ( ! triggerDirectChildren )
- {
- return;
- }
-
- Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) );
+ return;
}
- public static void TriggerAll( Action action, Node target, bool triggerDirectChildren )
+ #if !GD_SCRIPT_TRANSPILING
+
+ _isNetworkedTrigger = false;
+ _sendsSeed = false;
+ _sendsData = false;
+
+ #endif
+
+ _OnTrigger();
+
+ #if !GD_SCRIPT_TRANSPILING
+
+ SendOverNetwork();
+
+ #endif
+
+ }
+
+ protected virtual void _OnTrigger()
+ {
+
+ }
+
+ #if !GD_SCRIPT_TRANSPILING
+
+ NetworkNodeSlot _seedSlot = new NetworkNodeSlot();
+ NetworkNodeSlot _dataSlot = new NetworkNodeSlot();
+ NetworkNodeSlot _seedAndDataSlot = new NetworkNodeSlot();
+
+ protected void SendOverNetwork()
+ {
+ // check which type
+ // seed data => type
+ // 0 0 => vanilla
+ // 1 0 => with seed
+ // 0 1 => with data
+ // 1 1 => with seed + data
+ }
+
+ protected override List CreateNetworkNodeMembers()
+ {
+ return new List()
{
- if ( action != null )
+ _networkNodeSlot,
+ _seedSlot,
+ _dataSlot,
+ _seedAndDataSlot
+ };
+ }
+
+ protected void _OnNetworkTrigger( int seed, BitView data )
+ {
+ _isNetworkedTrigger = true;
+ _receivedNetworkSeed = seed;
+ _receivedNetworkData = data;
+
+ _OnTrigger();
+
+ _isNetworkedTrigger = false;
+ }
+
+ bool _isNetworkedTrigger = false;
+ int _receivedNetworkSeed = -1;
+ int _sendingNetworkSeed = -1;
+
+ bool _sendsSeed = false;
+ bool _sendsData = false;
+
+ BitView _sendingNetworkData;
+ BitView _receivedNetworkData;
+
+ public bool isNetworkedTrigger => _isNetworkedTrigger;
+
+ static readonly int maxNetworkSeed = Mathf.RoundToInt( Mathf.Pow( 2, 30 ) );
+
+ protected int networkSeed
+ {
+ get
+ {
+ if ( _isNetworkedTrigger )
{
- Action.Trigger( action );
-
+ return _receivedNetworkSeed;
+ }
+
+ if ( _sendsSeed )
+ {
+ return _sendingNetworkSeed;
}
- if ( ! triggerDirectChildren )
- {
- return;
- }
+ _sendingNetworkSeed = GodotRandom.Get().IntegerExclusive( 0, maxNetworkSeed );
+ _sendsSeed = true;
- Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) );
+ return _sendingNetworkSeed;
}
}
-}
\ No newline at end of file
+ protected BitView GetNetworkData( BitView view )
+ {
+ if ( _isNetworkedTrigger )
+ {
+ return _receivedNetworkData;
+ }
+
+ _sendingNetworkData = view;
+ _sendsData = true;
+ return _sendingNetworkData;
+ }
+
+
+
+ public static void Trigger( Action action )
+ {
+ if ( action == null )
+ {
+ return;
+ }
+
+ action.Trigger();
+ }
+
+ public static void TriggerAll( Action[] actions, Node target, bool triggerDirectChildren, Action caller = null )
+ {
+ if ( actions != null )
+ {
+ for ( int i = 0; i < actions.Length; i++ )
+ {
+ Action.Trigger( actions[ i ] );
+ }
+ }
+
+ if ( ! triggerDirectChildren )
+ {
+ return;
+ }
+
+ Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) );
+ }
+
+ public static void TriggerAll( Action action, Node target, bool triggerDirectChildren )
+ {
+ if ( action != null )
+ {
+ Action.Trigger( action );
+
+ }
+
+ if ( ! triggerDirectChildren )
+ {
+ return;
+ }
+
+ Nodes.ForEachDirectChild( target, ( a ) => Trigger( a ) );
+ }
+
+ #endif
+}
+
diff --git a/Runtime/Actions/Audio/MusicChannel.cs b/Runtime/Actions/Audio/MusicChannel.cs
new file mode 100644
index 0000000..3ab0cd8
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicChannel.cs
@@ -0,0 +1,17 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MusicChannel:Resource
+{
+ [Export]
+ public string playerName = "";
+
+ [Export]
+ public StringName audioBus = "";
+
+}
+
diff --git a/Runtime/Actions/Audio/MusicChannel.cs.uid b/Runtime/Actions/Audio/MusicChannel.cs.uid
new file mode 100644
index 0000000..8b98c4a
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicChannel.cs.uid
@@ -0,0 +1 @@
+uid://cs3ypfgd1r603
diff --git a/Runtime/Actions/Audio/MusicChannelPlayer.cs b/Runtime/Actions/Audio/MusicChannelPlayer.cs
new file mode 100644
index 0000000..0693e0c
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicChannelPlayer.cs
@@ -0,0 +1,89 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MusicChannelPlayer:Node
+{
+ [Export]
+ public MusicChannel channel;
+
+ [Export]
+ public MusicData currentMusic;
+
+ [Export]
+ public AudioStreamPlayer currentPlayer;
+
+
+ public void TweenVolume( AudioStreamPlayer target, float duration, float toVolume, bool clear, System.Action onReady = null )
+ {
+ var tl = TimeLineManager.Ensure( null );
+ var start = tl.position;
+ var fromVolume = target.VolumeLinear;
+
+ TimeLineManager.ScheduleSpanIn( tl, 0, duration,
+ ( span, type )=>
+ {
+ if ( ! GodotObject.IsInstanceValid( target ) )
+ {
+ return;
+ }
+
+ var lerpedVolume = Mathf.Lerp( fromVolume, toVolume, span.phase );
+ target.VolumeLinear = lerpedVolume;
+
+ if ( type == TimeLineSpanUpdateType.End && clear )
+ {
+ if ( clear )
+ {
+ ClearAudioPlayer( target );
+ }
+
+ if ( onReady != null )
+ {
+ onReady();
+ }
+
+ }
+
+ },
+ this
+ );
+ }
+
+ async void ClearAudioPlayer( AudioStreamPlayer target )
+ {
+ await this.RequestNextFrame();
+ target.DeleteSelf();
+ }
+
+ public void SchedulePlayer( MusicData nextMusic, float duration, System.Action onReady )
+ {
+ if ( currentMusic != null )
+ {
+ this.LogInfo( "Muting:", currentMusic );
+ TweenVolume( currentPlayer, duration, 0f, true );
+ currentMusic = null;
+ currentPlayer = null;
+ }
+
+ this.LogInfo( "Playing:", nextMusic );
+
+ var name = FilePath.Absolute( nextMusic.audio.ResourcePath ).fileName;
+ var nextPlayer = this.CreateChild( "Player " + name );
+ nextPlayer.VolumeLinear = 0f;
+ nextPlayer.Stream = nextMusic.audio;
+ nextPlayer.PitchScale = MathAudio.SemitonesToFrequencyScaler( nextMusic.pitchSemitonesOffset );
+ nextPlayer.Bus = channel.audioBus;
+
+ currentMusic = nextMusic;
+ currentPlayer = nextPlayer;
+ TweenVolume( nextPlayer, duration, nextMusic.volume, false, onReady );
+
+ nextPlayer.Play();
+ }
+
+}
+
diff --git a/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid b/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid
new file mode 100644
index 0000000..19ee9e4
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicChannelPlayer.cs.uid
@@ -0,0 +1 @@
+uid://nwt0qlwimulf
diff --git a/Runtime/Actions/Audio/MusicData.cs b/Runtime/Actions/Audio/MusicData.cs
new file mode 100644
index 0000000..f23b550
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicData.cs
@@ -0,0 +1,26 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MusicData: Resource
+{
+ [Export]
+ public Godot.AudioStream audio;
+
+ [Export( PropertyHint.Range, "0,1")]
+ public float volume = 1f;
+
+ [Export( PropertyHint.Range, "-36,36")]
+ public float pitchSemitonesOffset = 0f;
+
+ public override string ToString()
+ {
+ var prefix = pitchSemitonesOffset == 0 ? "+/-" : pitchSemitonesOffset > 0 ? "+" : "";
+ return "MusicData: " + (100 * volume)._FF() + "% (" + prefix + pitchSemitonesOffset + " st) " + audio.ResourcePath;
+ }
+
+}
+
diff --git a/Runtime/Actions/Audio/MusicData.cs.uid b/Runtime/Actions/Audio/MusicData.cs.uid
new file mode 100644
index 0000000..0b9cc40
--- /dev/null
+++ b/Runtime/Actions/Audio/MusicData.cs.uid
@@ -0,0 +1 @@
+uid://b5443aoeefkin
diff --git a/Runtime/Actions/Audio/ScheduleMusic.cs b/Runtime/Actions/Audio/ScheduleMusic.cs
new file mode 100644
index 0000000..e726bad
--- /dev/null
+++ b/Runtime/Actions/Audio/ScheduleMusic.cs
@@ -0,0 +1,42 @@
+
+using System;
+using Godot;
+
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Tween.svg")]
+public partial class ScheduleMusic:SequenceAction
+{
+ [Export]
+ public float duration = 0;
+
+ [Export]
+ public MusicData musicData;
+
+ [Export]
+ public MusicChannel channel;
+
+
+ protected override void _OnTrigger()
+ {
+ this.LogInfo( "Scheduling:", musicData );
+ var id = DispatchStart();
+
+ var audioManager = Unique.Get();
+ var player = audioManager.GetPlayer( channel );
+
+ player.SchedulePlayer(
+ musicData, Mathf.Max( 0.0f, duration), ()=>
+ {
+ DispatchEnd( id );
+ }
+ );
+
+ }
+
+
+
+
+}
diff --git a/Runtime/Actions/Audio/ScheduleMusic.cs.uid b/Runtime/Actions/Audio/ScheduleMusic.cs.uid
new file mode 100644
index 0000000..2475fd5
--- /dev/null
+++ b/Runtime/Actions/Audio/ScheduleMusic.cs.uid
@@ -0,0 +1 @@
+uid://tnm5c1nt0plk
diff --git a/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs
new file mode 100644
index 0000000..3965ed6
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs
@@ -0,0 +1,55 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class CompositorEffectSetting:NumberAppSetting
+ {
+ [Export]
+ public float userRangeToEffectRange = 1f/100f;
+
+ [Export]
+ public CompositorEffect compositorEffect;
+
+ [Export]
+ public string effectSettingName = "";
+
+ public enum TargetType
+ {
+ Float,
+ Int,
+ Bool
+ }
+
+ [Export]
+ public TargetType targetType = TargetType.Float;
+
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ var floatValue = RegexUtility.ParseFloat( stringValue );
+
+ var effectValue = floatValue * userRangeToEffectRange;
+
+ var member = effectSettingName;
+
+ if ( TargetType.Float == targetType )
+ {
+ ReflectionHelper.SetValue( compositorEffect, member, effectValue );
+ }
+ else if ( TargetType.Int == targetType )
+ {
+ ReflectionHelper.SetValue( compositorEffect, member, (int)effectValue );
+ }
+ else if ( TargetType.Bool == targetType )
+ {
+ ReflectionHelper.SetValue( compositorEffect, member, effectValue > 0 );
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid
new file mode 100644
index 0000000..8e8611a
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs.uid
@@ -0,0 +1 @@
+uid://fvqabvh4as0i
diff --git a/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres
index a79fd9b..567356f 100644
--- a/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres
+++ b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres
@@ -1,13 +1,46 @@
-[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=5 format=3 uid="uid://4iqfk01k81nc"]
+[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=13 format=3 uid="uid://4iqfk01k81nc"]
[ext_resource type="Script" uid="uid://b3kfbhiwqt26o" path="res://addons/rokojori_action_library/Runtime/App/Settings/AppSettingsCategory.cs" id="1_g7ii0"]
[ext_resource type="Resource" uid="uid://0itt52s066qp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres" id="2_xi6qd"]
[ext_resource type="Resource" uid="uid://bpfrw7y8jx2wp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres" id="3_g7ii0"]
[ext_resource type="Resource" uid="uid://cec7500hcn1e0" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres" id="3_xi6qd"]
+[ext_resource type="Resource" uid="uid://bd8cja8453an4" path="res://Rendering/FX-Anti-Aliasing.tres" id="4_27xtl"]
+[ext_resource type="Script" uid="uid://bgw3wuqxbwrb0" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs" id="5_fe0r4"]
+[ext_resource type="Script" uid="uid://fvqabvh4as0i" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/CompositorEffectSetting.cs" id="6_ajjd7"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="7_4upb4"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="8_pdrnl"]
+
+[sub_resource type="CompositorEffect" id="CompositorEffect_b71pn"]
+resource_local_to_scene = false
+resource_name = ""
+enabled = true
+effect_callback_type = 4
+needs_motion_vectors = false
+needs_normal_roughness = false
+script = ExtResource("5_fe0r4")
+amount = 4.0
+compositorEffectID = ExtResource("4_27xtl")
+metadata/_custom_type_script = "uid://bgw3wuqxbwrb0"
+
+[sub_resource type="Resource" id="Resource_nhpaj"]
+script = ExtResource("8_pdrnl")
+en = "FX Anti-Aliasing"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="Resource" id="Resource_6o5ni"]
+script = ExtResource("6_ajjd7")
+compositorEffect = SubResource("CompositorEffect_b71pn")
+effectSettingName = "amount"
+max = 400.0
+defaultValue = 100.0
+stepSize = 10.0
+suffix = ExtResource("7_4upb4")
+title = SubResource("Resource_nhpaj")
+metadata/_custom_type_script = "uid://fvqabvh4as0i"
[resource]
script = ExtResource("1_g7ii0")
title = ExtResource("3_g7ii0")
id = "graphics"
-settings = [ExtResource("3_xi6qd"), ExtResource("2_xi6qd")]
+settings = [ExtResource("2_xi6qd"), ExtResource("3_xi6qd"), SubResource("Resource_6o5ni")]
metadata/_custom_type_script = "uid://b3kfbhiwqt26o"
diff --git a/Runtime/Audio/AudioManager/AudioManager.cs b/Runtime/Audio/AudioManager/AudioManager.cs
index 4c62ff0..2d1110d 100644
--- a/Runtime/Audio/AudioManager/AudioManager.cs
+++ b/Runtime/Audio/AudioManager/AudioManager.cs
@@ -12,6 +12,24 @@ namespace Rokojori
Dictionary _lastPlayTime = new Dictionary();
+ [Export]
+ public MusicChannelPlayer[] players = [];
+
+ public MusicChannelPlayer GetPlayer( MusicChannel channel )
+ {
+ var player = players.Find( p => p.channel == channel );
+
+ if ( player == null )
+ {
+ player = this.CreateChild( channel.playerName );
+ player.channel = channel;
+
+ players = players.Add( player );
+ }
+
+ return player;
+ }
+
public float GetLastPlayed( AudioFlag selectorFlag )
{
if ( ! _lastPlayTime.ContainsKey( selectorFlag ) )
diff --git a/Runtime/Cameras/PostProcess/PostProcessVolume.cs b/Runtime/Cameras/PostProcess/PostProcessVolume.cs
index 95ea673..26967b5 100644
--- a/Runtime/Cameras/PostProcess/PostProcessVolume.cs
+++ b/Runtime/Cameras/PostProcess/PostProcessVolume.cs
@@ -20,6 +20,8 @@ namespace Rokojori
[Export]
public int priority = 0;
+ public int combinedPriority => ! enabled ? -1 : priority;
+
[Export]
public PostProcessVolumeEffect[] effects;
diff --git a/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs b/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs
index 5c085bc..c7e61cc 100644
--- a/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs
+++ b/Runtime/Cameras/PostProcess/PostProcessVolumeEffect.cs
@@ -90,18 +90,18 @@ namespace Rokojori
continue;
}
- if ( volumes[ i ].priority < priorities[ j ] )
+ if ( volumes[ i ].combinedPriority < priorities[ j ] )
{
continue;
}
- if ( priorities[ j ] < volumes[ i ].priority )
+ if ( priorities[ j ] < volumes[ i ].combinedPriority )
{
valueWeights[ j ] = 0f;
floatValues[ j ].SetFloatValue( 0f );
}
- priorities[ j ] = volumes[ i ].priority;
+ priorities[ j ] = volumes[ i ].combinedPriority;
var value = floatValues[ j ].GetFloatValue();
@@ -200,18 +200,18 @@ namespace Rokojori
continue;
}
- if ( volumes[ i ].priority < priorities[ j ] )
+ if ( volumes[ i ].combinedPriority < priorities[ j ] )
{
continue;
}
- if ( priorities[ j ] < volumes[ i ].priority )
+ if ( priorities[ j ] < volumes[ i ].combinedPriority )
{
valueWeights[ j ] = 0f;
colorValues[ j ].value = new Color( 0, 0, 0, 0 );
}
- priorities[ j ] = volumes[ i ].priority;
+ priorities[ j ] = volumes[ i ].combinedPriority;
var weight = volumes[ i ].combinedWeight;
diff --git a/Runtime/Files/FilePath.cs b/Runtime/Files/FilePath.cs
index 3ea41ed..4bd760b 100644
--- a/Runtime/Files/FilePath.cs
+++ b/Runtime/Files/FilePath.cs
@@ -45,7 +45,7 @@ namespace Rokojori
{
get
{
- if ( _fileName == null)
+ if ( _fileName == null )
{
_fileName = Path.GetFileNameWithoutExtension( path );
}
diff --git a/Runtime/Godot/Extensions/ControlExtensions.cs b/Runtime/Godot/Extensions/ControlExtensions.cs
new file mode 100644
index 0000000..b12664d
--- /dev/null
+++ b/Runtime/Godot/Extensions/ControlExtensions.cs
@@ -0,0 +1,18 @@
+using Godot;
+
+using System.Collections.Generic;
+using System;
+using System.Threading.Tasks;
+using System.Reflection;
+
+namespace Rokojori
+{
+ public static class ControlExtensions
+ {
+ public static Vector2 GetCenter( this Control control )
+ {
+ return control.Position + control.Size * 0.5f;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Godot/Extensions/ControlExtensions.cs.uid b/Runtime/Godot/Extensions/ControlExtensions.cs.uid
new file mode 100644
index 0000000..ab26833
--- /dev/null
+++ b/Runtime/Godot/Extensions/ControlExtensions.cs.uid
@@ -0,0 +1 @@
+uid://b1efhjod1yomf
diff --git a/Runtime/Graphs/Trees/TreeWalker.cs b/Runtime/Graphs/Trees/TreeWalker.cs
index 1d641bc..5a61af4 100644
--- a/Runtime/Graphs/Trees/TreeWalker.cs
+++ b/Runtime/Graphs/Trees/TreeWalker.cs
@@ -470,6 +470,23 @@ namespace Rokojori
return null;
}
+ public T GetParentWithType( N node )
+ {
+ var p = Parent( node );
+
+ while ( p != null )
+ {
+ if ( p is T t )
+ {
+ return t;
+ }
+
+ p = Parent( p );
+ }
+
+ return default(T);
+ }
+
public int GetAncestorDistance( N child, N ancestor )
{
if ( ancestor == null )
diff --git a/Runtime/Math/Math3D.cs b/Runtime/Math/Math3D.cs
index f68cf2c..3046c94 100644
--- a/Runtime/Math/Math3D.cs
+++ b/Runtime/Math/Math3D.cs
@@ -12,7 +12,36 @@ namespace Rokojori
{
X, Y, Z
}
-
+
+
+ public static float ComputeLineDistance( IEnumerable points )
+ {
+ return ComputeLineDistance( points, ( p ) => p );
+ }
+
+ public static float ComputeLineDistance( IEnumerable points, System.Func getPosition )
+ {
+ var distance = 0f;
+
+ Vector3? before = null;
+
+ foreach ( var p in points )
+ {
+ if ( before == null )
+ {
+ before = getPosition( p );
+ continue;
+ }
+
+ var b = (Vector3)before;
+ var position = getPosition( p );
+ distance += ( b - position ).Length();
+ before = position;
+ }
+
+ return distance;
+ }
+
public static float LookingAtEachOtherAngle( Vector3 lookDirectionA, Vector3 lookDirectionB )
{
return Dot( lookDirectionA, lookDirectionB );
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs
new file mode 100644
index 0000000..131d252
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs
@@ -0,0 +1,62 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool, GlobalClass]
+ public partial class AltByAngle_SplineUpGen:SplineUpGeneratorStrategy
+ {
+ [Export]
+ public Vector3 alternativeUp;
+
+ [Export( PropertyHint.Range, "0,90")]
+ public float angleThresholdDegrees = 5f;
+
+ [Export]
+ public bool forceFromPositions = false;
+
+ public override Vector3 ComputeUp(
+ int numReferences,
+ System.Func getPosition,
+ System.Func getForward,
+ System.Func getUp
+ )
+ {
+ var usePositions = forceFromPositions || getForward == null;
+
+ if ( numReferences <= 0 || usePositions && numReferences == 1 )
+ {
+ return Vector3.Up;
+ }
+
+ var forward = usePositions ? ( getPosition( 1 ) - getPosition( 0 ) ) : getForward( 0 );
+
+ var forwardNormalized = forward.Normalized();
+
+ var xzLength = forwardNormalized.XZ().Length();
+
+ if ( xzLength == 0 )
+ {
+ return alternativeUp;
+ }
+
+ var yawDir = new Vector2( xzLength, Mathf.Abs( forwardNormalized.Y ) );
+ var angle = yawDir.Angle();
+
+ if ( angle > angleThresholdDegrees )
+ {
+ return Vector3.Up;
+ }
+
+ var amount = 1f - ( angle / angleThresholdDegrees );
+
+ var slerped = Vector3.Up.Slerp( alternativeUp, amount );
+
+ return slerped;
+
+ }
+
+ }
+}
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid
new file mode 100644
index 0000000..cc389af
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/AltByAngle_SplineUpGen.cs.uid
@@ -0,0 +1 @@
+uid://d0yj01q8hppot
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs
new file mode 100644
index 0000000..6b7660d
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs
@@ -0,0 +1,24 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool, GlobalClass]
+ public partial class Constant_SplineUpGen:SplineUpGeneratorStrategy
+ {
+ [Export]
+ public Vector3 constantUp;
+ public override Vector3 ComputeUp(
+ int getNumReferences,
+ System.Func getPosition,
+ System.Func getForward,
+ System.Func getUp
+ )
+ {
+ return constantUp;
+ }
+
+ }
+}
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid
new file mode 100644
index 0000000..3f28b3c
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/Constant_SplineUpGen.cs.uid
@@ -0,0 +1 @@
+uid://c257amlha7moj
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs
new file mode 100644
index 0000000..bb13fce
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs
@@ -0,0 +1,19 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool, GlobalClass]
+ public abstract partial class SplineUpGeneratorStrategy:Resource
+ {
+ public abstract Vector3 ComputeUp(
+ int getNumReferences,
+ System.Func getPosition,
+ System.Func getForward,
+ System.Func getUp
+ );
+
+ }
+}
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid
new file mode 100644
index 0000000..54f4249
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/SplineUpGeneratorStrategy.cs.uid
@@ -0,0 +1 @@
+uid://vl5tkdm7lnc0
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs
new file mode 100644
index 0000000..40e2a13
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs
@@ -0,0 +1,24 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool, GlobalClass]
+ public partial class WorldUp_SplineUpGen:SplineUpGeneratorStrategy
+ {
+ public static readonly WorldUp_SplineUpGen instance = new WorldUp_SplineUpGen();
+
+ public override Vector3 ComputeUp(
+ int getNumReferences,
+ System.Func getPosition,
+ System.Func getForward,
+ System.Func getUp
+ )
+ {
+ return Vector3.Up;
+ }
+
+ }
+}
diff --git a/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid
new file mode 100644
index 0000000..b1ebb00
--- /dev/null
+++ b/Runtime/Procedural/Parametric/Spline/SplineUp/WorldUp_SplineUpGen.cs.uid
@@ -0,0 +1 @@
+uid://d3x1tsjce28xe
diff --git a/Runtime/Random/RandomEngine.cs b/Runtime/Random/RandomEngine.cs
index fea771b..425265c 100644
--- a/Runtime/Random/RandomEngine.cs
+++ b/Runtime/Random/RandomEngine.cs
@@ -375,6 +375,20 @@ namespace Rokojori
return selection;
}
+ public T FromWeightedElements( IList elements, Func getWeight )
+ {
+ var weights = new List( elements.Count );
+
+ foreach ( var e in elements )
+ {
+ weights.Add( getWeight( e ) );
+ }
+
+ var index = IndexFromUnnormalizedWeights( weights );
+
+ return elements[ index ];
+ }
+
public int IndexFromUnnormalizedWeights( List weights, float sumWeights = 0 )
{
if ( sumWeights <= 0 )
diff --git a/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs b/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs
index a13d6f8..a18878c 100644
--- a/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs
+++ b/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs
@@ -53,6 +53,12 @@ namespace Rokojori
[Export( PropertyHint.Range, "0,1") ]
public float normalEdgeAmountMax = 0.15f;
+ [Export( PropertyHint.Range, "0,1") ]
+ public float normalZFilterWeight = 1f;
+
+ [Export]
+ public float normalZDiffWeight = 1.0f;
+
[Export]
public float zTreshold = 0.1f;
@@ -77,6 +83,9 @@ namespace Rokojori
[Export ]
public Vector2 zOutput = new Vector2( 0f, 1f );
+ [Export( PropertyHint.Range, "0,1") ]
+ public float debugViewZ = 0;
+
RG_ScreenColorTexure screenColorTexture;
RG_ScreenDepthTexture screenDepthTexture;
@@ -186,7 +195,12 @@ namespace Rokojori
rimContrast,
rimStrength,
Mathf.Pow( 10f, outlineWidth ),
- edgeDistanceFade
+ edgeDistanceFade,
+
+ debugViewZ,
+ normalZFilterWeight,
+ normalZDiffWeight,
+ 0f
);
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png
new file mode 100644
index 0000000..91c06a1
Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png differ
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import
new file mode 100644
index 0000000..bd8d87b
--- /dev/null
+++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dpagciclpro4l"
+path="res://.godot/imported/good-graphics.png-71a1fa2dc0da1570f69568e7db0767eb.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/good-graphics.png"
+dest_files=["res://.godot/imported/good-graphics.png-71a1fa2dc0da1570f69568e7db0767eb.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png
new file mode 100644
index 0000000..4730607
Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png differ
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import
new file mode 100644
index 0000000..3ba349e
--- /dev/null
+++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://drfvhbwh15gkg"
+path="res://.godot/imported/star-glow-blur.png-142c3c2b394a06f53c56fa99ae68e47e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png"
+dest_files=["res://.godot/imported/star-glow-blur.png-142c3c2b394a06f53c56fa99ae68e47e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png
new file mode 100644
index 0000000..8aa4fb4
Binary files /dev/null and b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png differ
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import
new file mode 100644
index 0000000..7a8ec14
--- /dev/null
+++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cb7n8cuuqqgn1"
+path="res://.godot/imported/star-glow.png-183351a5bd2df4d5391efd4f3d4d6420.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png"
+dest_files=["res://.godot/imported/star-glow.png-183351a5bd2df4d5391efd4f3d4d6420.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres
index 636c1fc..f636fde 100644
--- a/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres
+++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow.tres
@@ -4,8 +4,9 @@
[ext_resource type="Script" uid="uid://cx5qcow1mmd11" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorEffectOwner.cs" id="2_bfksq"]
[ext_resource type="Script" uid="uid://comuvej4dr22k" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/RokojoriCompositorEffectID.cs" id="3_eyvih"]
[ext_resource type="Script" uid="uid://t5g1g1uv5yrj" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Overlay/TextureOverlay/TextureOverlayEffect.cs" id="4_chktd"]
-[ext_resource type="Texture2D" uid="uid://cqaqvhmyuo56d" path="res://VFX/Compositor Effects/Star Glow/star-glow-blur.png" id="5_1gqhf"]
+[ext_resource type="Texture2D" uid="uid://cb7n8cuuqqgn1" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow.png" id="5_chktd"]
[ext_resource type="Script" uid="uid://cqkrgyuerq50a" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Distortion/EllispeDistortion/EllipseDistortionEffect.cs" id="6_t8xaw"]
+[ext_resource type="Texture2D" uid="uid://drfvhbwh15gkg" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorVFXPresets/Glow/Rainbow Star Glow Assets/star-glow-blur.png" id="7_1gqhf"]
[ext_resource type="Script" uid="uid://6jkixa201wux" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Glow/ChromaticBloom/ChromaticBloomEffect.cs" id="7_g2w8j"]
[ext_resource type="Script" uid="uid://pevgspwywsxi" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Color/HSLAdjustment/HSLAdjustmentEffect.cs" id="8_bfeok"]
[ext_resource type="Script" uid="uid://ckixweetchlo0" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorVFXPreset.cs" id="9_fgrt2"]
@@ -27,16 +28,15 @@ script = ExtResource("1_e74ec")
member = "opacity"
curve = SubResource("Curve_xhmdb")
-[sub_resource type="Resource" id="Resource_1ntwo"]
+[sub_resource type="Resource" id="Resource_mdsx3"]
script = ExtResource("2_bfksq")
[sub_resource type="Resource" id="Resource_5jnfl"]
script = ExtResource("3_eyvih")
-owner = SubResource("Resource_1ntwo")
+owner = SubResource("Resource_mdsx3")
[sub_resource type="Gradient" id="Gradient_qf8q3"]
-offsets = PackedFloat32Array(0.34812286, 0.70307165, 0.8988327)
-colors = PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1, 16.420414, 16.420414, 16.420414, 1)
+offsets = PackedFloat32Array(0.60144925, 1)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_cqn6v"]
gradient = SubResource("Gradient_qf8q3")
@@ -44,10 +44,7 @@ use_hdr = true
fill = 1
fill_from = Vector2(0.5, 0.50427353)
-[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_g6idi"]
-load_path = "res://.godot/imported/star-glow.png-61f0458024aeba1668f3516b3db84782.ctex"
-
-[sub_resource type="CompositorEffect" id="CompositorEffect_e74ec"]
+[sub_resource type="CompositorEffect" id="CompositorEffect_wpvj8"]
resource_local_to_scene = false
resource_name = ""
enabled = true
@@ -55,10 +52,10 @@ effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("4_chktd")
-opacity = 0.0
+opacity = 0.5578947
blendMode = 1
-overlayTexture = SubResource("CompressedTexture2D_g6idi")
-overlayTint = Color(1, 1, 1, 0.050980393)
+overlayTexture = ExtResource("5_chktd")
+overlayTint = Color(1, 1, 1, 0.33333334)
tiling = Vector2(9, 5.0625)
scrolling = Vector2(0.22, 0.012)
maskTexture = SubResource("GradientTexture2D_cqn6v")
@@ -82,7 +79,7 @@ curve = SubResource("Curve_xhmdb")
[sub_resource type="Resource" id="Resource_qf8q3"]
script = ExtResource("3_eyvih")
-owner = SubResource("Resource_1ntwo")
+owner = SubResource("Resource_mdsx3")
[sub_resource type="Gradient" id="Gradient_7ucn0"]
offsets = PackedFloat32Array(0.08171206, 0.57587546, 1)
@@ -94,7 +91,7 @@ use_hdr = true
fill = 1
fill_from = Vector2(0.5, 0.50427353)
-[sub_resource type="CompositorEffect" id="CompositorEffect_bfksq"]
+[sub_resource type="CompositorEffect" id="CompositorEffect_ysmsc"]
resource_local_to_scene = false
resource_name = ""
enabled = true
@@ -102,10 +99,10 @@ effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("4_chktd")
-opacity = 0.0
+opacity = 0.5578947
blendMode = 1
-overlayTexture = ExtResource("5_1gqhf")
-overlayTint = Color(1, 1, 1, 0.21568628)
+overlayTexture = ExtResource("7_1gqhf")
+overlayTint = Color(1, 1, 1, 0)
tiling = Vector2(1, 0.5625)
scrolling = Vector2(-0.1, -0.01)
maskTexture = SubResource("GradientTexture2D_su8gi")
@@ -126,9 +123,9 @@ curve = SubResource("Curve_nxurn")
[sub_resource type="Resource" id="Resource_slvrs"]
script = ExtResource("3_eyvih")
-owner = SubResource("Resource_1ntwo")
+owner = SubResource("Resource_mdsx3")
-[sub_resource type="CompositorEffect" id="CompositorEffect_eyvih"]
+[sub_resource type="CompositorEffect" id="CompositorEffect_t5au6"]
resource_local_to_scene = false
resource_name = ""
enabled = true
@@ -136,7 +133,7 @@ effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("6_t8xaw")
-distortionAmount = 0.0
+distortionAmount = 0.12
ellipseScale = 1.138
ringsDistribution = 0.7727
animationTargets = [SubResource("Resource_35pef")]
@@ -151,12 +148,13 @@ point_count = 3
script = ExtResource("1_e74ec")
member = "amount"
curve = SubResource("Curve_71075")
+curveScale = 0.2
[sub_resource type="Resource" id="Resource_bhyc7"]
script = ExtResource("3_eyvih")
-owner = SubResource("Resource_1ntwo")
+owner = SubResource("Resource_mdsx3")
-[sub_resource type="CompositorEffect" id="CompositorEffect_chktd"]
+[sub_resource type="CompositorEffect" id="CompositorEffect_ixqtu"]
resource_local_to_scene = false
resource_name = ""
enabled = true
@@ -164,11 +162,11 @@ effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("7_g2w8j")
-amount = 0.0
+amount = 0.1691
num = 3
distortionAmount = 0.4369
distortionAngle = 168.8496
-distortionAngleSpeed = 10.0
+distortionAngleSpeed = 40.0
smearingSteps = 24
smearing = 1.2171
redShift = 0.2239
@@ -196,9 +194,9 @@ curve = SubResource("Curve_su8gi")
[sub_resource type="Resource" id="Resource_7jt2s"]
script = ExtResource("3_eyvih")
-owner = SubResource("Resource_1ntwo")
+owner = SubResource("Resource_mdsx3")
-[sub_resource type="CompositorEffect" id="CompositorEffect_1gqhf"]
+[sub_resource type="CompositorEffect" id="CompositorEffect_m7r8b"]
resource_local_to_scene = false
resource_name = ""
enabled = true
@@ -206,7 +204,7 @@ effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("8_bfeok")
-amount = 0.0
+amount = 1.0
saturationOffset = 30.0
saturationGamma = 37.9747
lightnessOffset = 2.0
@@ -217,5 +215,5 @@ metadata/_custom_type_script = "uid://pevgspwywsxi"
[resource]
script = ExtResource("9_fgrt2")
-effects = [SubResource("CompositorEffect_e74ec"), SubResource("CompositorEffect_bfksq"), SubResource("CompositorEffect_eyvih"), SubResource("CompositorEffect_chktd"), SubResource("CompositorEffect_1gqhf")]
+effects = [SubResource("CompositorEffect_wpvj8"), SubResource("CompositorEffect_ysmsc"), SubResource("CompositorEffect_t5au6"), SubResource("CompositorEffect_ixqtu"), SubResource("CompositorEffect_m7r8b")]
metadata/_custom_type_script = "uid://ckixweetchlo0"
diff --git a/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres b/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres
index 853563b..4b98dad 100644
--- a/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres
+++ b/Runtime/Rendering/Compositor/CompositorVFXPresets/Screen/Sketch.tres
@@ -1,8 +1,7 @@
-[gd_resource type="Resource" script_class="CompositorVFXPreset" load_steps=36 format=3 uid="uid://0blw3yhjw7y0"]
+[gd_resource type="Resource" script_class="CompositorVFXPreset" load_steps=35 format=3 uid="uid://0blw3yhjw7y0"]
[ext_resource type="Script" uid="uid://cx5qcow1mmd11" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/CompositorEffectOwner.cs" id="1_0ail8"]
[ext_resource type="Script" uid="uid://dvvfvlutisecy" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/AnimationTargets/CompFXMemberCurveTarget.cs" id="1_4xviq"]
-[ext_resource type="Resource" uid="uid://bwhnq7w0tpgv" path="res://VFX/Action FX Compositor Effect Layer.tres" id="2_4xviq"]
[ext_resource type="Script" uid="uid://comuvej4dr22k" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffectReferences/RokojoriCompositorEffectID.cs" id="2_tc21q"]
[ext_resource type="Script" uid="uid://bx4j8ic80vl7f" path="res://addons/rokojori_action_library/Runtime/Rendering/Compositor/CompositorEffects/Edge/DepthOutlines/DepthOutlinesEffect.cs" id="3_dryyw"]
[ext_resource type="Texture2D" uid="uid://c30nul6romace" path="res://addons/rokojori_action_library/Runtime/Procedural/Noise/RGB 3D Noise.png" id="5_orb2s"]
@@ -26,7 +25,6 @@ script = ExtResource("1_0ail8")
[sub_resource type="Resource" id="Resource_p64cs"]
script = ExtResource("2_tc21q")
owner = SubResource("Resource_4xviq")
-layer = ExtResource("2_4xviq")
[sub_resource type="Curve" id="Curve_7axlu"]
_data = [Vector2(0, 1), 0.0, -18.573792, 0, 0, Vector2(0.07774799, 0.15679264), -0.687919, -0.687919, 0, 0, Vector2(1, 0), -0.069252, 0.0, 0, 0]
@@ -91,7 +89,6 @@ metadata/_custom_type_script = "uid://dvvfvlutisecy"
[sub_resource type="Resource" id="Resource_hpfyh"]
script = ExtResource("2_tc21q")
owner = SubResource("Resource_4xviq")
-layer = ExtResource("2_4xviq")
[sub_resource type="Gradient" id="Gradient_frwbc"]
offsets = PackedFloat32Array(1)
@@ -135,7 +132,6 @@ metadata/_custom_type_script = "uid://dvvfvlutisecy"
[sub_resource type="Resource" id="Resource_gxlxg"]
script = ExtResource("2_tc21q")
owner = SubResource("Resource_4xviq")
-layer = ExtResource("2_4xviq")
[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_4n83u"]
load_path = "res://.godot/imported/RGB 3D Noise.png-daebfe00d2f3fcd5d3bc528f8a3972e1.ctex"
@@ -172,7 +168,6 @@ metadata/_custom_type_script = "uid://balixgskgouhm"
[sub_resource type="Resource" id="Resource_3tnad"]
script = ExtResource("2_tc21q")
owner = SubResource("Resource_4xviq")
-layer = ExtResource("2_4xviq")
[sub_resource type="CompositorEffect" id="CompositorEffect_hdnet"]
resource_local_to_scene = false
diff --git a/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl b/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl
index 5d53adf..6828d40 100644
--- a/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl
+++ b/Runtime/Rendering/RenderGraph/Nodes/Processors/Outlines/ZOutlines/ZOutlines.glsl
@@ -57,6 +57,11 @@ uniform Parameters
float outlineWidth;
float edgeDistanceFade;
+ float debugViewZ;
+ float normalFilterWeight;
+ float normalZDiffWeight;
+ float pad3;
+
} parameters;
@@ -144,6 +149,28 @@ float mapClamped( float value, float inMin, float inMax, float outMin, float out
return mix( outMin, outMax, normalizeToRange01( value, inMin, inMax ) );
}
+float edgeFilter( vec3 nA, vec3 nB, float zA, float zB, float zScale )
+{
+ float dotValue = dot( nA, nB );
+ float angleAmount = max( 0.0, 1.0 - dotValue );
+ angleAmount = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, angleAmount );
+
+ // Same direction => ( 1 - 0 ) => 1, edge
+ // Not same direction => ( 1 - 1 ) => 0, no edge
+
+ float normalizedZDiff = abs( zA - zB ) * parameters.normalZDiffWeight * zScale;
+ // 1 => big z distance
+ // 0 => close z
+
+ float zDiffAmount = clamp( normalizedZDiff, 0.0, 1.0 );
+ // 0 distance => close => edge
+ // 1 distance => far => no edge
+
+ float invZDIff = 1.0 - zDiffAmount;
+
+ return clamp( angleAmount + invZDIff, 0.0, 1.0 );
+}
+
void main( )
{
ivec2 size = imageSize( outputImage );
@@ -220,12 +247,35 @@ void main( )
float normalEdge = 0.0;
- normalEdge = max( normalEdge, 1.0 - dot( n11, n01 ) );
- normalEdge = max( normalEdge, 1.0 - dot( n11, n21 ) );
- normalEdge = max( normalEdge, 1.0 - dot( n11, n10 ) );
- normalEdge = max( normalEdge, 1.0 - dot( n11, n12 ) );
+ // float zDiffNormalizer = parameters.normalZDiffWeight;
- float edgeWeight = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, normalEdge );
+ // float zDiffAmount01 = max( 0.0, 1.0 - abs( z11 - z01 ) * zDiffNormalizer );
+ // float zDiffAmount21 = max( 0.0, 1.0 - abs( z11 - z21 ) * zDiffNormalizer );
+ // float zDiffAmount10 = max( 0.0, 1.0 - abs( z11 - z10 ) * zDiffNormalizer );
+ // float zDiffAmount12 = max( 0.0, 1.0 - abs( z11 - z12 ) * zDiffNormalizer );
+
+ // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n01 ) * zDiffAmount01 ) );
+ // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n21 ) * zDiffAmount21 ) );
+ // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n10 ) * zDiffAmount10 ) );
+ // normalEdge = max( normalEdge, 1.0 - ( dot( n11, n12 ) * zDiffAmount12 ) );
+
+ // normalEdge = max( normalEdge, edgeFilter( n11, n01, z11, z01, adaptiveScale ) );
+ // normalEdge = max( normalEdge, edgeFilter( n11, n21, z11, z21, adaptiveScale ) );
+ // normalEdge = max( normalEdge, edgeFilter( n11, n10, z11, z10, adaptiveScale ) );
+ // normalEdge = max( normalEdge, edgeFilter( n11, n12, z11, z12, adaptiveScale ) );
+
+
+ normalEdge += edgeFilter( n11, n01, z11, z01, adaptiveScale );
+ normalEdge += edgeFilter( n11, n21, z11, z21, adaptiveScale );
+ normalEdge += edgeFilter( n11, n10, z11, z10, adaptiveScale );
+ normalEdge += edgeFilter( n11, n12, z11, z12, adaptiveScale );
+
+ normalEdge /= 4.0;
+
+ // float edgeWeight = smoothstep( parameters.normalEdgeZMin, parameters.normalEdgeZMax, normalEdge );
+ float edgeWeight = normalEdge;
+
+ edgeWeight = mix( 1.0, edgeWeight, parameters.normalFilterWeight );
float edge = max( normalEdge * parameters.normalEdgeAmount, zEdge * parameters.zEdgeAmount * edgeWeight );
edge = clamp01( edge );
@@ -240,7 +290,11 @@ void main( )
vec4 edgeColor = SRGBtoLINEAR( vec4( parameters.edgeR, parameters.edgeG, parameters.edgeB, 1.0 ) );
// originalColor.rgb = mix( originalColor.rgb, vec3( 0.0, 0.0, 0.0 ), shadowAmount );
vec4 mixedColor = mix( originalColor, edgeColor, parameters.amount * edge );
-
+
+ if ( parameters.debugViewZ > 0.0 )
+ {
+ mixedColor.rgb = mix( mixedColor.rgb, vec3( normalEdge * 1.0 ), parameters.debugViewZ );
+ }
imageStore( outputImage, xy, mixedColor );
}
\ No newline at end of file
diff --git a/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres b/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres
index 52c7bef..2e682b6 100644
--- a/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres
+++ b/Runtime/Sensors/Default-Sensors/Default-Input-Icons-Library.tres
@@ -192,7 +192,7 @@ directionUpTexture = ExtResource("6_0hfff")
[sub_resource type="Resource" id="Resource_40bf3"]
script = ExtResource("2_4sutq")
-value = 0.7
+value = 1.5
unit = "em"
[sub_resource type="Resource" id="Resource_xrtll"]
@@ -274,7 +274,7 @@ backgroundTexture = ExtResource("21_hcyk3")
[resource]
script = ExtResource("1_urlfx")
fontSize = SubResource("Resource_40bf3")
-iconHeightInEm = 1.5
+iconHeightInEm = 3.0
mouseInputIcon = SubResource("Resource_34cgw")
keyboardKeys = SubResource("Resource_nkgsq")
keyboardModifiers = SubResource("Resource_wrdp7")
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres
index 50899c0..3bdfdf8 100644
--- a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres
@@ -1,11 +1,18 @@
-[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://cqatyb80rpor0"]
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=6 format=3 uid="uid://cqatyb80rpor0"]
[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_u5wou"]
[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_ibucs"]
+[ext_resource type="Script" uid="uid://cc8g4jmyrpehg" path="res://addons/rokojori_action_library/Runtime/Sensors/InputIcons/Types/GamePadAxisIcon.cs" id="2_n3xai"]
+
+[sub_resource type="Resource" id="Resource_yth0n"]
+script = ExtResource("2_n3xai")
+type = 1
+metadata/_custom_type_script = "uid://cc8g4jmyrpehg"
[sub_resource type="Resource" id="Resource_n3xai"]
script = ExtResource("2_ibucs")
inputActionName = "ui_left"
+inputIcons = [SubResource("Resource_yth0n")]
metadata/_custom_type_script = "uid://e7fduwypgvwr"
[resource]
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres
index d9fd33f..d4ea6e2 100644
--- a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres
@@ -1,11 +1,17 @@
-[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://dafu3alp6wr25"]
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=6 format=3 uid="uid://dafu3alp6wr25"]
[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_rqdfo"]
[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_oj4wy"]
+[ext_resource type="Script" uid="uid://cc8g4jmyrpehg" path="res://addons/rokojori_action_library/Runtime/Sensors/InputIcons/Types/GamePadAxisIcon.cs" id="2_tuqbj"]
+
+[sub_resource type="Resource" id="Resource_i2j76"]
+script = ExtResource("2_tuqbj")
+metadata/_custom_type_script = "uid://cc8g4jmyrpehg"
[sub_resource type="Resource" id="Resource_tuqbj"]
script = ExtResource("2_oj4wy")
inputActionName = "ui_right"
+inputIcons = [SubResource("Resource_i2j76")]
metadata/_custom_type_script = "uid://e7fduwypgvwr"
[resource]
diff --git a/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs b/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs
index 7cea961..b004a15 100644
--- a/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs
+++ b/Runtime/Sensors/DeviceFilters/LastActiveDeviceFilter.cs
@@ -24,6 +24,8 @@ namespace Rokojori
{
return false;
}
+
+ this.LogInfo( "Checking Icon:", device.GetType().Name, icon.GetType().Name );
return device.ContainsIcon( icon );
}
diff --git a/Runtime/Sensors/Devices/GamePadDevice.cs b/Runtime/Sensors/Devices/GamePadDevice.cs
index 4c87a5a..6793464 100644
--- a/Runtime/Sensors/Devices/GamePadDevice.cs
+++ b/Runtime/Sensors/Devices/GamePadDevice.cs
@@ -45,6 +45,8 @@ namespace Rokojori
return ci.icons.Length == 1 && ContainsIcon( ci.icons[ 0 ] );
}
+
+
return ReflectionHelper.IsTypeOneOf( icon,
typeof( GamePadAxisIcon ),
typeof( GamePadButtonIcon )
diff --git a/Runtime/Sensors/Devices/SensorDevice.cs b/Runtime/Sensors/Devices/SensorDevice.cs
index d7eac9e..f534b0b 100644
--- a/Runtime/Sensors/Devices/SensorDevice.cs
+++ b/Runtime/Sensors/Devices/SensorDevice.cs
@@ -6,7 +6,7 @@ namespace Rokojori
{
[Tool]
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/SensorGroup.svg")]
- public partial class SensorDevice: Resource
+ public abstract partial class SensorDevice: Resource
{
public virtual string GetInfo()
diff --git a/Runtime/Sensors/InputIcons/Types/SensorIcon.cs b/Runtime/Sensors/InputIcons/Types/SensorIcon.cs
index fac4797..5a950ef 100644
--- a/Runtime/Sensors/InputIcons/Types/SensorIcon.cs
+++ b/Runtime/Sensors/InputIcons/Types/SensorIcon.cs
@@ -11,6 +11,13 @@ namespace Rokojori
[Export]
public Sensor sensor;
+ public static SensorIcon Create( Sensor sensor )
+ {
+ var si = new SensorIcon();
+ si.sensor = sensor;
+ return si;
+ }
+
public override bool Equals( object obj )
{
var value = obj as SensorIcon;
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc
new file mode 100644
index 0000000..0a36d53
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc
@@ -0,0 +1,9 @@
+
+vec3 translation;
+mat3 rotation;
+
+#include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc"
+mat4 combined = createMat4FromBasisAndOrigin( rotation, translation );
+
+MODELVIEW_MATRIX *= combined;
+MODELVIEW_NORMAL_MATRIX *= rotation;
\ No newline at end of file
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid
new file mode 100644
index 0000000..c850fcb
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-ApplyModelViewMatrix.gdshaderinc.uid
@@ -0,0 +1 @@
+uid://k6hhfjejkh5p
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc
new file mode 100644
index 0000000..e75021f
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc
@@ -0,0 +1,4 @@
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc"
+
+#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc"
+#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Bezier.gdshaderinc"
\ No newline at end of file
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid
new file mode 100644
index 0000000..3cb28b8
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc.uid
@@ -0,0 +1 @@
+uid://c1f4jt1qpwk42
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc
new file mode 100644
index 0000000..89262ff
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc
@@ -0,0 +1,24 @@
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc"
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc"
+
+instance uniform vec3 startPosition;
+instance uniform vec3 startForward;
+instance uniform vec3 startUp;
+instance uniform float startNormalizedDistance;
+
+instance uniform vec3 endPosition;
+instance uniform vec3 endForward;
+instance uniform vec3 endUp;
+instance uniform float endNormalizedDistance;
+
+instance uniform float lineLength;
+
+uniform float scaling:hint_range(0.0,2.0) = 1.0;
+uniform int positionInterpolationMode = 0;
+uniform float bezierCurvature:hint_range(0.0,0.5) = 0.3333333333;
+uniform float rationalCurvature :hint_range(0.0,0.5) = 0.5;
+uniform float rationalWeighting :hint_range(0.0,1.0) = 0.5;
+
+uniform int rotationInterpolationMode = 0;
+varying float normalizedDistance;
+varying float t;
\ No newline at end of file
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid
new file mode 100644
index 0000000..c004245
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc.uid
@@ -0,0 +1 @@
+uid://buho4jxq4dkpl
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc
new file mode 100644
index 0000000..c72b92b
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc
@@ -0,0 +1,86 @@
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Includes.gdshaderinc"
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Variables.gdshaderinc"
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc"
+
+// vec3 translation; mat3 rotation;
+
+ if ( positionInterpolationMode == 0 )
+ {
+ translation = mix( startPosition, endPosition, t );
+ }
+ else if ( positionInterpolationMode == 1 )
+ {
+ float controlLength = length( endPosition - startPosition ) * bezierCurvature;
+ vec3 c0 = startPosition + normalize( startForward ) * controlLength;
+ vec3 c1 = endPosition - normalize( endForward ) * controlLength;
+
+ translation = cubicBezier( t, startPosition, c0, c1, endPosition );
+ }
+ else if ( positionInterpolationMode == 2 )
+ {
+ float controlLength = length( endPosition - startPosition ) * rationalCurvature;
+ vec3 c0 = startPosition + normalize( startForward ) * controlLength;
+ vec3 c1 = endPosition - normalize( endForward ) * controlLength;
+
+ translation = rationalCubicBezier( t,
+ startPosition, c0, c1, endPosition,
+ 1.0, rationalWeighting, rationalWeighting, 1.0
+ );
+
+ }
+
+
+ if ( rotationInterpolationMode == 0 )
+ {
+ vec3 forward = normalize( mix( startForward, endForward, t ) );
+ vec3 up = normalize( mix( startUp, endUp, t ) );
+ rotation = lookRotation( forward, up );
+
+ }
+ else if ( rotationInterpolationMode == 1 )
+ {
+ vec4 startRotation = quaternionFromLookRotation( startForward, startUp );
+ vec4 endRotation = quaternionFromLookRotation( endForward, endUp );
+
+ vec4 qRotation = quaternionSlerp( startRotation, endRotation, t );
+ rotation = quaternionToRotationMatrix( qRotation );
+ }
+ else if ( rotationInterpolationMode == 2 )
+ {
+
+ float controlLength = length( endPosition - startPosition ) * bezierCurvature;
+ vec3 c0 = startPosition + normalize( startForward ) * controlLength;
+ vec3 c1 = endPosition - normalize( endForward ) * controlLength;
+
+ vec3 forward = normalize( cubicBezierDerivative( t, startPosition, c0, c1, endPosition ) );
+ vec3 up = normalize( mix( startUp, endUp, t ) );
+ rotation = lookRotation( forward, up );
+ }
+ else if ( rotationInterpolationMode == 3 )
+ {
+ vec3 lineDirection = normalize( endPosition - startPosition );
+ vec3 forward = t < 0.5 ? mix( startForward, lineDirection, t * 2.0 ) :
+ mix( lineDirection, endForward, ( t - 0.5 ) * 2.0 );
+ vec3 up = normalize( mix( startUp, endUp, t ) );
+ rotation = lookRotation( forward, up );
+ }
+ else if ( rotationInterpolationMode == 4 )
+ {
+ bool isStart = t < 0.5;
+ vec3 lineDirection = normalize( endPosition - startPosition );
+ vec3 centerUp = normalize( mix( startUp, endUp, 0.5 ) );
+
+ vec3 forwardA = isStart ? startForward : lineDirection;
+ vec3 forwardB = isStart ? lineDirection : endForward;
+
+ vec3 upA = isStart ? startUp : centerUp;
+ vec3 upB = isStart ? centerUp : endUp;
+
+ vec4 rotationA = quaternionFromLookRotation( forwardA, upA );
+ vec4 rotationB = quaternionFromLookRotation( forwardB, upB );
+
+ float rt = isStart ? ( t * 2.0 ) : ( ( t -0.5 ) * 2.0 );
+
+ vec4 qRotation = quaternionSlerp( rotationA, rotationB, rt );
+ rotation = quaternionToRotationMatrix( qRotation );
+ }
\ No newline at end of file
diff --git a/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid
new file mode 100644
index 0000000..3f747d0
--- /dev/null
+++ b/Runtime/Shading/Library/LineVFX/LineVFX-Vertex.gdshaderinc.uid
@@ -0,0 +1 @@
+uid://dairdipwvqk75
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs
new file mode 100644
index 0000000..8fdf53f
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs
@@ -0,0 +1,177 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+namespace Rokojori;
+
+public class GDScriptFromCSAST
+{
+ public GDScriptGeneratorClass gdClass = new GDScriptGeneratorClass();
+ public string rokojoriPrefix = "RJ_";
+
+
+ public static string CStoGDVariable( string csName )
+ {
+ var sb = new StringBuilder();
+ var hasUnderscore = false;
+ var wordStarted = false;
+
+ for ( int i = 0; i < csName.Length; i++ )
+ {
+ if ( char.IsUpper( csName[ i ] ) )
+ {
+ if ( ! hasUnderscore && wordStarted )
+ {
+ sb.Append( "_" );
+ hasUnderscore = true;
+ }
+
+ sb.Append( char.ToLower( csName[ i ] ) );
+ wordStarted = true;
+
+ }
+ else
+ {
+ sb.Append( csName[ i ] );
+ hasUnderscore = csName[ i ] == '_';
+
+ if ( ! hasUnderscore )
+ {
+ wordStarted = true;
+ }
+ }
+ }
+
+ return sb.ToString();
+ }
+
+
+ public string GetClassName( string className, string ns )
+ {
+ if ( ns.StartsWith( "Rokojori" ) )
+ {
+ return rokojoriPrefix + className;
+ }
+
+ return className;
+ }
+
+ public void Convert( CSFileRoot root )
+ {
+ var walker = root.walker;
+ var csClass = walker.Find( root, n => n is CSClassDeclaration, true ) as CSClassDeclaration;
+
+ gdClass.name = GetClassName( csClass.GetClassName(), "Rokojori" );
+
+ if ( csClass.objectTail != null && csClass.objectTail.inheritanceDeclaration != null )
+ {
+ gdClass.extendingClassName = GetClassName( csClass.objectTail.GetExtendingObject(), "Rokojori" );
+ }
+
+ var atts = CSModifierAttributesParser.GetAttributes( csClass.attributeBrackets );
+
+ RJLog.Log( "Att:", atts.Map( a => "'" + a + "'" ) );
+
+ atts.ForEach(
+ ( att )=>
+ {
+
+ if ( att == "Tool" )
+ {
+ gdClass.annotations.Add( "tool" );
+ }
+ else if ( att.StartsWith( "Icon" ) )
+ {
+ var lcAtt = ( att[ 0 ] + "" ).ToLower() + att.Substring( 1 );
+ gdClass.annotations.Add( lcAtt );
+ }
+ }
+ );
+
+
+ var members = new List();
+
+ walker.Iterate( csClass,
+ n =>
+ {
+ if ( n is CSEnumDeclaration en )
+ {
+ var enumType = new GDScriptGeneratorEnum();
+ enumType.name = en.objectName.match;
+
+ var values = en.objectBody.children.FilterType( );
+ enumType.values =values.Map( v => v.GetEnumName() );
+
+ gdClass.members.Add( enumType );
+
+ return;
+ }
+
+ if ( ! ( n is CSMemberDeclaration ) )
+ {
+ return;
+ }
+
+
+ var m = n as CSMemberDeclaration;
+
+ GDScriptGeneratorMember gdMember = null;
+
+ if ( m is CSFieldDeclaration f )
+ {
+ var gdField = new GDScriptGeneratorField();
+ gdField.name = CStoGDVariable( f.GetMemberName() );
+ gdField.memberType = f.GetMemberType();
+
+ gdMember = gdField;
+ }
+ else if ( m is CSMethodMemberDeclaration me )
+ {
+ var gdMethod = new GDScriptGeneratorMethod();
+ gdMethod.name = me.isContructor ? "_init" : CStoGDVariable( me.GetMemberName() );
+ gdMethod.memberType = me.GetMemberType();
+ gdMethod.isConstructor = me.isContructor;
+
+ if ( me.parametersContent != null )
+ {
+ me.parametersContent.children.ForEach(
+ ( c ) =>
+ {
+ var p = c as CSParameterDeclaration;
+
+ var gdParameter = new GDScriptGeneratorParameter();
+ gdParameter.name = p.GetParameterName();
+ gdParameter.parameterType = p.GetParameterType();
+
+ gdMethod.parameters.Add( gdParameter );
+
+ if ( p.parameterValue != null )
+ {
+ gdParameter.parameterValue = p.GetParameterValue();
+ }
+ }
+ );
+ }
+
+ gdMember = gdMethod;
+ }
+
+ if ( gdMember == null )
+ {
+ return;
+ }
+
+ if ( CSModifierAttributesParser.IsExported( m.attributeBrackets ) )
+ {
+ gdMember.annotations.Add( "export" );
+ }
+
+ gdClass.members.Add( gdMember );
+
+ },
+ false
+ );
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid
new file mode 100644
index 0000000..f1707d2
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptFromCSAST.cs.uid
@@ -0,0 +1 @@
+uid://cgi2d0hhd5d6t
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs
new file mode 100644
index 0000000..585981c
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs
@@ -0,0 +1,28 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGenerator
+{
+ public static readonly string GD_SCRIPT_TRANSPILING = "GD_SCRIPT_TRANSPILING";
+ public List gdClasses = new List();
+
+
+ public void Generate( string outputPath )
+ {
+ gdClasses.ForEach(
+ ( gd )=>
+ {
+ var source = gd.Generate();
+ RJLog.Log( "GD Script from:", gd.name, "\n" + source );
+ var path = FilePath.Join( outputPath, gd.name + ".gd" );
+
+ RJLog.Log( "GD Script Save to:", path );
+ FilesSync.SaveUTF8( path, source );
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid
new file mode 100644
index 0000000..dd97096
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGenerator.cs.uid
@@ -0,0 +1 @@
+uid://duym6hiqy40dh
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs
new file mode 100644
index 0000000..d733200
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs
@@ -0,0 +1,53 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGeneratorClass
+{
+ public List annotations = [];
+ public string name;
+ public string extendingClassName;
+ public List members = [];
+
+ StringBuilder sb = new StringBuilder();
+
+ public string Generate()
+ {
+ sb.Append( "\n" );
+
+ annotations.ForEach(
+ annotation =>
+ {
+ sb.Append( "@" );
+ sb.Append( annotation );
+ sb.Append( "\n" );
+ }
+ );
+
+ AddClassHeader();
+ sb.Append( "\n" );
+
+ members.ForEach( m =>
+ {
+ m.Generate( sb );
+ sb.Append( "\n" );
+ });
+
+ return sb.ToString();
+ }
+
+ void AddClassHeader()
+ {
+ sb.Append( "class_name " + name );
+
+ if ( extendingClassName != null )
+ {
+ sb.Append( " extends " + extendingClassName );
+ }
+
+ sb.Append( "\n" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid
new file mode 100644
index 0000000..b74042d
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorClass.cs.uid
@@ -0,0 +1 @@
+uid://dvt4yeqpmmrur
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs
new file mode 100644
index 0000000..631599e
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs
@@ -0,0 +1,32 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGeneratorEnum:GDScriptGeneratorMember
+{
+ public List values = new List();
+
+ public override void Generate( StringBuilder sb )
+ {
+ sb.Append( "enum " + name + "\n" );
+ sb.Append( "{\n" );
+
+ for ( int i = 0; i < values.Count; i ++ )
+ {
+ var ending = "\n";
+
+ if ( i != ( values.Count - 1 ) )
+ {
+ ending = ",\n";
+ }
+
+ sb.Append( " " + values[ i ] + ending );
+ }
+
+ sb.Append( "}\n" );
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid
new file mode 100644
index 0000000..9be4ffc
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorEnum.cs.uid
@@ -0,0 +1 @@
+uid://eqbysvejll0q
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs
new file mode 100644
index 0000000..81919f6
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs
@@ -0,0 +1,24 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGeneratorField:GDScriptGeneratorMember
+{
+ public override void Generate( StringBuilder sb )
+ {
+ annotations.ForEach(
+ ( an )=>
+ {
+ sb.Append( "@" );
+ sb.Append( an );
+ sb.Append( "\n" );
+ }
+ );
+
+ sb.Append( "var " + name + ": " + memberType + "; " );
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid
new file mode 100644
index 0000000..e78ebb0
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorField.cs.uid
@@ -0,0 +1 @@
+uid://51c533ougel
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs
new file mode 100644
index 0000000..7684242
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs
@@ -0,0 +1,17 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public abstract class GDScriptGeneratorMember
+{
+ public string name;
+ public string memberType;
+ public List annotations = [];
+
+
+ public abstract void Generate( StringBuilder sb );
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid
new file mode 100644
index 0000000..e864a06
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMember.cs.uid
@@ -0,0 +1 @@
+uid://bnl20gavp2hi2
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs
new file mode 100644
index 0000000..16fd301
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs
@@ -0,0 +1,75 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGeneratorMethod:GDScriptGeneratorMember
+{
+ public List parameters = [];
+ public string body = "";
+ public bool isConstructor = false;
+
+ public override void Generate( StringBuilder sb )
+ {
+ sb.Append( "\n" );
+ sb.Append( "func " + name + "(" );
+
+ var first = true;
+
+ if ( parameters.Count > 0 )
+ {
+ sb.Append( " " );
+ }
+
+ parameters.ForEach(
+ ( p ) =>
+ {
+ if ( first )
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append( ", " );
+ }
+
+ p.Generate( sb );
+
+ }
+ );
+
+ if ( parameters.Count > 0 )
+ {
+ sb.Append( " " );
+ }
+
+ if ( isConstructor )
+ {
+ sb.Append( "):\n" );
+ }
+ else
+ {
+ sb.Append( ") -> " + memberType + ":\n" );
+ }
+
+
+ if ( string.IsNullOrEmpty( body ) )
+ {
+ sb.Append( " pass" );
+ }
+ else
+ {
+ sb.Append( body );
+ }
+
+
+ sb.Append( "\n" );
+ sb.Append( "## ---");
+ sb.Append( "\n" );
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid
new file mode 100644
index 0000000..1b2114c
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorMethod.cs.uid
@@ -0,0 +1 @@
+uid://ddcgqrokie8en
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs
new file mode 100644
index 0000000..9004d41
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs
@@ -0,0 +1,24 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Rokojori;
+
+public class GDScriptGeneratorParameter
+{
+ public string name;
+ public string parameterType;
+ public string parameterValue;
+
+ public void Generate( StringBuilder sb )
+ {
+ sb.Append( name + ": " + parameterType );
+
+ if ( parameterValue != null )
+ {
+ sb.Append( " = " + parameterValue );
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid
new file mode 100644
index 0000000..c786982
--- /dev/null
+++ b/Runtime/Text/CodeGenerators/GDScript/GDScriptGeneratorParameter.cs.uid
@@ -0,0 +1 @@
+uid://bg3fdqomodfh2
diff --git a/Runtime/Text/Lexing/Lexer.cs b/Runtime/Text/Lexing/Lexer.cs
index 9b66233..eff29e6 100644
--- a/Runtime/Text/Lexing/Lexer.cs
+++ b/Runtime/Text/Lexing/Lexer.cs
@@ -42,6 +42,10 @@ namespace Rokojori
public bool hasError => _hasError;
+ public virtual void Clear()
+ {
+ _hasError = false;
+ }
void AddMatcher( LexerMatcher matcher )
{
@@ -74,6 +78,16 @@ namespace Rokojori
AddMatcher( type, new Regex( regex ), mode, nextMode );
}
+ public virtual bool HasVariableMatch( string type )
+ {
+ return LexerMatcherLibrary.CwordMatcher.type == type || LexerMatcherLibrary.CFunctionMatcher.type == type;
+ }
+
+ public static bool IsVariableMatchType( string type )
+ {
+ return LexerMatcherLibrary.CwordMatcher.type == type || LexerMatcherLibrary.CFunctionMatcher.type == type;
+ }
+
public LexerMatcher GetMatcher( string source, string mode ="" )
{
var matchers = _modes[ mode ];
diff --git a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs
similarity index 92%
rename from Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs
rename to Runtime/Text/Lexing/LexerLibrary/CSLexer.cs
index 198f374..e051c33 100644
--- a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs
+++ b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs
@@ -12,11 +12,11 @@ namespace Rokojori
}
- public class CSharpLexer:Lexer
+ public class CSLexer:Lexer
{
public static List Lex( string source )
{
- var lexer = new CSharpLexer();
+ var lexer = new CSLexer();
var events = lexer.LexToList( source );
if ( lexer.hasError )
@@ -36,8 +36,7 @@ namespace Rokojori
}
public static List GetAllObjectDefinitions( List tokens )
- {
-
+ {
var START = Trillean.True;
var END = Trillean.False;
@@ -72,7 +71,7 @@ namespace Rokojori
return sequences.Map( s => new CSharpObjectDefinition{ type = s[ 0 ], name = s[ s.Count - 1 ] } );
}
- public CSharpLexer()
+ public CSLexer()
{
AddAllMatchers(
LexerMatcherLibrary.SingleLineCommentMatcher,
@@ -87,7 +86,7 @@ namespace Rokojori
LexerMatcherLibrary.WhiteSpaceMatcher,
LexerMatcherLibrary.LogicMatcher,
LexerMatcherLibrary.BracketMatcher,
- LexerMatcherLibrary.AccessModifierMatcher,
+ LexerMatcherLibrary.CSAccessModifierMatcher,
LexerMatcherLibrary.ClassMatcher,
LexerMatcherLibrary.EnumMatcher,
LexerMatcherLibrary.StructMatcher,
@@ -95,6 +94,8 @@ namespace Rokojori
LexerMatcherLibrary.RecordMatcher,
LexerMatcherLibrary.OperatorMatcher,
LexerMatcherLibrary.CFunctionMatcher,
+ LexerMatcherLibrary.UsingMatcher,
+ LexerMatcherLibrary.NamespaceMatcher,
LexerMatcherLibrary.CwordMatcher,
LexerMatcherLibrary.AnySymbolMatcher
);
diff --git a/Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs.uid b/Runtime/Text/Lexing/LexerLibrary/CSLexer.cs.uid
similarity index 100%
rename from Runtime/Text/Lexing/LexerLibrary/CSharpLexer.cs.uid
rename to Runtime/Text/Lexing/LexerLibrary/CSLexer.cs.uid
diff --git a/Runtime/Text/Lexing/LexerMatcherLibrary.cs b/Runtime/Text/Lexing/LexerMatcherLibrary.cs
index 1a8686f..fa998f9 100644
--- a/Runtime/Text/Lexing/LexerMatcherLibrary.cs
+++ b/Runtime/Text/Lexing/LexerMatcherLibrary.cs
@@ -18,6 +18,11 @@ namespace Rokojori
public static readonly LexerMatcher PHPWordMatcher =
new LexerMatcher( "PHPWord", @"\$?[a-zA-Z_]\w*" );
+ public static readonly LexerMatcher UsingMatcher =
+ new LexerMatcher( "Using", @"using" );
+
+ public static readonly LexerMatcher NamespaceMatcher =
+ new LexerMatcher( "Namespace", @"namespace" );
public static readonly LexerMatcher CSS_ClassSelectorMatcher =
new LexerMatcher( "CSS_ClassSelector", @"\.[a-zA-Z_](\w|\-)*" );
@@ -58,7 +63,7 @@ namespace Rokojori
new LexerMatcher( "Logic", "if|else|switch|do|while|for|break|continue|return" );
public static readonly LexerMatcher OperatorMatcher =
- new LexerMatcher( "Operator", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\+\\=)|(?:\\*\\=)|(?:\\-\\=)|(?:\\/\\=)|\\+|\\-|\\*|\\/|\\^|\\||\\~|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" );
+ new LexerMatcher( "Operator", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\+\\=)|(?:\\*\\=)|(?:\\-\\=)|(?:\\/\\=)|(?:\\=\\>)|\\+|\\-|\\*|\\/|\\^|\\|\\||\\||\\~|\\&\\&|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" );
public static readonly LexerMatcher BracketMatcher =
new LexerMatcher( "Bracket", @"\(|\)|\[|\]|\{|\}" );
@@ -87,6 +92,9 @@ namespace Rokojori
public static readonly LexerMatcher AccessModifierMatcher =
new LexerMatcher( "AccessModifier", @"\b(?:public|protected|private|const)\b" );
+ public static readonly LexerMatcher CSAccessModifierMatcher =
+ new LexerMatcher( "AccessModifier", @"\b(?:public|protected|private|const|partial|internal|abstract|static|sealed|virtual|override|readonly|ref|unsafe|new)\b" );
+
public static readonly LexerMatcher SingleLineCommentMatcher =
new LexerMatcher( "SingleLineComment", @"//.*" );
diff --git a/Runtime/Text/Parsing/AST/ASTFileRoot.cs b/Runtime/Text/Parsing/AST/ASTFileRoot.cs
new file mode 100644
index 0000000..59bc54c
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTFileRoot.cs
@@ -0,0 +1,18 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface ASTFileRoot
+{
+ public string GetFilePath();
+ public string GetSource();
+ public TextLinesMapper GetTextLinesMapper();
+ public Parser GetParser();
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid b/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid
new file mode 100644
index 0000000..d9acadb
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTFileRoot.cs.uid
@@ -0,0 +1 @@
+uid://blsoe8oknj2wy
diff --git a/Runtime/Text/Parsing/AST/ASTNode.cs b/Runtime/Text/Parsing/AST/ASTNode.cs
new file mode 100644
index 0000000..f1e43ee
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTNode.cs
@@ -0,0 +1,918 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public abstract class ASTNode
+{
+ Parser _parser;
+
+ public Parser parser
+ {
+ get
+ {
+ if ( _parser == null )
+ {
+ var root = this is ASTFileRoot ? (ASTFileRoot) this :
+ ( ASTWalker.instance.GetParentWithType( this ) as ASTFileRoot );
+
+ _parser = root.GetParser();
+ }
+
+ return _parser;
+ }
+ }
+
+ public ASTNode parent;
+ public List children = [];
+
+
+ int ComputeIndex( int index )
+ {
+ return index >= 0 ? index : ( children.Count + index );
+ }
+
+
+ public string CreateDebugTreeInfo()
+ {
+ var walker = ASTWalker.instance;
+
+ var end = walker.IterationEndOf( this );
+
+ var it = this;
+
+ var depthMap = new Dictionary();
+
+ Func GetDepth = null;
+
+ GetDepth = n =>
+ {
+ if ( depthMap.ContainsKey( n ) )
+ {
+ return depthMap[ n ];
+ }
+
+ if ( n.parent == null )
+ {
+ return 0;
+ }
+
+ var parentDepth = GetDepth( n.parent );
+ var ownDepth = parentDepth + 1;
+
+ depthMap[ n ] = ownDepth;
+
+ return ownDepth;
+ };
+
+ var lines = new List();
+
+ while ( it != end )
+ {
+ var indent = " ".Repeat( GetDepth( it ) );
+ var info = indent + "-- [#" + it.childIndex + "] " + it.GetType();
+
+
+ if ( it is Token tk )
+ {
+ info += "'" + tk.match+ "'";
+ }
+ else
+ {
+ info += "(" + it.children.Count + ")";
+ }
+
+ lines.Add( info );
+
+ it = walker.NextNode( it );
+ }
+
+ return lines.Join( "\n");
+
+ }
+
+ public List GrabTokenRange( Token start, Token end, bool filter )
+ {
+ if ( start.parent != this || end.parent != this )
+ {
+ RJLog.Error( "Tokens are not children of this", GetType().Name, "start:", start, "end:", end );
+ return null;
+ }
+
+ var startIndex = start.childIndex;
+ var endIndex = end.childIndex;
+
+ // RJLog.Log( "Grabbing Child Range:", startIndex, "to", endIndex, " num children:", children.Count );
+ var unfiltered = children.Range( start.childIndex, end.childIndex );
+ var filtered = unfiltered.Filter( n => n is Token && ( ! filter || ! n.IsIgnoreToken() ) );
+ return filtered.Map( f => f as Token );
+ }
+
+ public void MergeChildren( int start, int length, ASTNode merger )
+ {
+ merger.parent = this;
+ merger.children = children.Sub( start, length );
+ merger.children.ForEach( c => c.parent = merger );
+
+ children.ReplaceRange( start, length, [ merger ] );
+ }
+
+ public T MergeInner( int indexStart, int indexEnd ) where T:ASTNode,new()
+ {
+ var start = indexStart + 1;
+ var length = indexEnd - start;
+
+ return MergeChildrenWith( start, length );
+ }
+
+ public T MergeOuter( int indexStart, int indexEnd ) where T:ASTNode,new()
+ {
+ var start = indexStart;
+ var length = indexEnd - start + 1;
+
+ return MergeChildrenWith( start, length );
+ }
+
+ public T MergeOuter( ASTNode nodeStart, ASTNode nodeEnd ) where T:ASTNode,new()
+ {
+ if ( nodeStart.parent != this || nodeEnd.parent != this )
+ {
+ RJLog.Error( "Nodes are not child of this node:", this,
+ "start:", nodeStart, "start is child:", nodeStart.parent == this,
+ "end:", nodeEnd, "end is child:", nodeEnd.parent == this
+ );
+ return null;
+ }
+
+ var startIndex = nodeStart.childIndex;
+ var endIndex = children.FindIndex( startIndex, c => c == nodeEnd );
+
+ return MergeOuter( startIndex, endIndex );
+ }
+
+ public T MergeInner( ASTNode nodeStart, ASTNode nodeEnd ) where T:ASTNode,new()
+ {
+ if ( nodeStart.parent != this || nodeEnd.parent != this )
+ {
+ RJLog.Error( "Nodes are not child of this node:", this, "start:", nodeStart, "end:", nodeEnd );
+ return null;
+ }
+
+ var startIndex = nodeStart.childIndex;
+ var endIndex = children.FindIndex( startIndex, c => c == nodeEnd );
+
+ RJLog.Log( "Merging:", startIndex, endIndex );
+
+ if ( startIndex == -1 || endIndex == - 1 )
+ {
+ return null;
+ }
+
+ return MergeInner( startIndex, endIndex );
+ }
+
+ public int childIndex => parent == null ? -1 : parent.children.IndexOf( this );
+ public int reverseIndexOffset => parent == null ? -1 :
+ ( ( parent.children.Count - 1 ) - childIndex );
+
+ public string CombinedMatch()
+ {
+ if ( this is Token tk )
+ {
+ return tk.match;
+ }
+
+ var tokens = children.FilterType();
+
+ return tokens.Map( t => t.match ).Join( "" );
+ }
+
+ public void ExpandToPrevious( ASTNode previousSibling )
+ {
+ if ( parent == null || previousSibling == null || parent != previousSibling.parent )
+ {
+ RJLog.Error( "Invalid sibling", previousSibling?.GetType().Name ?? "null" );
+ return;
+ }
+
+ var start = previousSibling.childIndex;
+ var length = childIndex - start;
+
+ var beforeCount = children.Count;
+
+ var range = parent.children.Sub( start, length );
+ parent.children.RemoveRange( start, length );
+
+ range.ForEach( r => r.parent = this );
+ children.Prepend( range );
+
+ RJLog.Log( "Expanded from", beforeCount, "to", children.Count, "( " + length + " )" );
+ }
+
+ public ASTWalker walker => Singleton.Get();
+
+ public T GetParentWithType()
+ {
+ return walker.GetParentWithType( this );
+ }
+
+ public T MergeChildrenWith( int start, int length ) where T:ASTNode, new()
+ {
+ var t = new T();
+ MergeChildren( start, length, t );
+ return t;
+ }
+
+ public int FindIndex( System.Func evaluator, int offset = 0, int end = -1, bool forward = true )
+ {
+ offset = ComputeIndex( offset );
+ end = ComputeIndex( end );
+
+ var change = forward ? 1 : -1;
+ end += change;
+
+ // RJLog.Log( "start:", offset, "end:", end, "direction:", change > 0 ? "forward" : "backwards", change, "children:", children.Count );
+ for ( int i = offset; i != end; i += change )
+ {
+ if ( evaluator( children[ i ] ) )
+ {
+ return i;
+ }
+ else
+ {
+ // RJLog.Log( "not matching", children[ i ] );
+ }
+ }
+
+ return -1;
+ }
+
+ public ASTNode FindNode( System.Func evaluator, int offset = 0 )
+ {
+ var index = FindIndex( evaluator, offset );
+ return index == -1 ? null : children[ index ];
+ }
+
+ public int ReverseFindBracketOpenerIndex( string open, string close, int closeIndex )
+ {
+ closeIndex --;
+ var count = 1;
+
+ // RJLog.Log( "ReverseFindBracketOpenerIndex", open, close, closeIndex );
+
+ for ( int i = closeIndex; i >= 0; i-- )
+ {
+
+ var child = children[ i ];
+
+ // RJLog.Log( "index", i, count, child );
+
+ if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, open ) )
+ {
+ count --;
+
+ if ( count == 0 )
+ {
+ return i;
+ }
+ }
+ else if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, close ) )
+ {
+ count ++;
+ }
+
+ // RJLog.Log( "index", i, count );
+ }
+
+ return -1;
+ }
+
+ public int FindBracketCloserIndex( string open, string close, int openIndex )
+ {
+ openIndex ++;
+ var count = 1;
+
+ // RJLog.Log( "ReverseFindBracketOpenerIndex", open, close, closeIndex );
+
+ for ( int i = openIndex; i < children.Count; i++ )
+ {
+
+ var child = children[ i ];
+
+ // RJLog.Log( "index", i, count, child );
+
+ if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, close ) )
+ {
+ count --;
+
+ if ( count == 0 )
+ {
+ return i;
+ }
+ }
+ else if ( child.IsToken( LexerMatcherLibrary.BracketMatcher, open ) )
+ {
+ count ++;
+ }
+
+ // RJLog.Log( "index", i, count );
+ }
+
+ return -1;
+ }
+
+ public List GetSeparatorIndices( string separator, int start, int end, List blockPredicates = null, Lexer lexer = null )
+ {
+ lexer = lexer ?? new CSLexer();
+
+ var hasBlockPredicated = blockPredicates != null;
+
+ var separatorPredicate = TokenPredicateData.Lexed( lexer, separator );
+
+ if ( ! hasBlockPredicated )
+ {
+ blockPredicates = new List();
+
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "<" ) );
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, ">" ) );
+
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "[" ) );
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "]" ) );
+
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "(" ) );
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, ")" ) );
+
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "{" ) );
+ blockPredicates.Add( TokenPredicateData.Lexed( lexer, "}" ) );
+ }
+
+ var bcCounter = new List();
+
+ for ( int i = 0; i < blockPredicates.Count; i+= 2 )
+ {
+ bcCounter.Add( 0 );
+ }
+
+
+ var inBlock = false;
+
+ var indices = new List();
+
+ for ( int i = start + 1; i < end; i++ )
+ {
+ if ( children[ i ].IsIgnoreToken() )
+ {
+ continue;
+ }
+
+ if ( ! inBlock && separatorPredicate.Matches( children[ i ] ) )
+ {
+ indices.Add( i );
+ continue;
+ }
+
+ var bcIndex = blockPredicates.FindIndex( bc => bc.Matches( children[ i ] ) );
+
+ if ( bcIndex == -1 )
+ {
+ continue;
+ }
+
+ var index = bcIndex / 2;
+ var isUp = index * 2 == bcIndex;
+
+ var change = isUp ? 1 : -1;
+
+ bcCounter[ index ] += change;
+
+ var sum = 0; bcCounter.ForEach( b => sum += b );
+ inBlock = sum != 0;
+
+ }
+
+ return indices;
+ }
+
+ public void CreateSeperatedList( string separator, Action callback = null ) where T:ASTNode, new()
+ {
+ var indices = GetSeparatorIndices( separator, -1, children.Count );
+
+ indices.Insert( 0, -1 );
+ indices.Add( children.Count );
+
+ RJLog.Log( "Parameters Indices:", indices.Count, CombinedMatch() );
+
+ var nodes = new List();
+
+
+ for ( int i = 0; i < indices.Count - 1; i++ )
+ {
+ var start = indices[ i ] + 1;
+ var end = indices[ i + 1 ] - 1;
+
+ var t = new T();
+
+ RJLog.Log( "Parameters Grabbing Indices:", start, end );
+
+ if ( start > end || start < 0 || end < 0 || start >= children.Count || end >= children.Count )
+ {
+ RJLog.Error( "Invalid seperation indices", this, CombinedMatch() );
+ throw new Exception();
+ }
+
+ if ( start == end )
+ {
+ t.children = [ children[ start ] ];
+ }
+ else
+ {
+ t.children = children.Range( start, end );
+ }
+
+ t.children.ForEach( c => c.parent = t );
+ nodes.Add( t );
+ t.parent = this;
+ }
+
+ children = nodes;
+
+ if ( callback != null )
+ {
+ children.ForEach( n => callback( n as T ) );
+ }
+
+ }
+
+
+ public Token FindBracketCloser( string open, string close, int openIndex )
+ {
+ var index = FindBracketCloserIndex( open, close, openIndex );
+
+ return index == -1 ? null : ( children[ index ] as Token );
+ }
+
+ public Token ReverseFindBracketOpener( string open, string close, int closeIndex )
+ {
+ var index = ReverseFindBracketOpenerIndex( open, close, closeIndex );
+
+ return index == -1 ? null : ( children[ index ] as Token );
+ }
+
+ public bool IsToken( LexerMatcher matcher, string match = null )
+ {
+ return this is Token tk && tk.Is( matcher, match );
+ }
+
+ public bool IsToken( string type, string match = null )
+ {
+ return this is Token tk && tk.Is( type, match );
+ }
+
+ public bool IsAnyTokenOf( LexerMatcher[] matchers )
+ {
+ return this is Token tk && tk.lexerEvent.IsAnyOf( matchers );
+ }
+
+ public bool IsAnyTokenOf( List predicates )
+ {
+ return this is Token && predicates.Find( p => p.Matches( this ) ) != null ;
+ }
+
+ public bool IsIgnoreToken()
+ {
+ return IsAnyTokenOf( LexerMatcherLibrary.Ignore );
+ }
+
+ public int IndexOffset( int index, int offset )
+ {
+ if ( offset < 0 )
+ {
+ while ( offset < 0 )
+ {
+ index = PreviousIndex( index );
+ offset ++;
+ }
+ }
+ else
+ {
+ while ( offset > 0 )
+ {
+ index = NextIndex( index );
+ offset--;
+ }
+ }
+
+ return index;
+ }
+
+ public int PreviousIndex( int index )
+ {
+ for ( int i = index - 1; i >= 0; i-- )
+ {
+ if ( children[ i ].IsIgnoreToken() )
+ {
+ continue;
+ }
+
+ return i;
+ }
+
+ return -1;
+ }
+
+ public ASTNode PreviousNode( int index )
+ {
+ return IndexToChildNode( PreviousIndex( index ) );
+ }
+
+ public int NextIndex( int index )
+ {
+ for ( int i = index + 1; i < children.Count; i++ )
+ {
+ if ( children[ i ].IsIgnoreToken() )
+ {
+ continue;
+ }
+
+ return i;
+ }
+
+ return -1;
+ }
+
+ public ASTNode NextNode( int index )
+ {
+ return IndexToChildNode( NextIndex( index ) );
+ }
+
+ ASTNode IndexToChildNode( int index )
+ {
+ return index == -1 ? null : children[ index ];
+ }
+
+ public Token FindToken( LexerMatcher matcher, int offset = 0 )
+ {
+ return FindToken( matcher, null, offset );
+ }
+
+ public Token FindToken( TokenPredicateData predicateData, int offset = 0 )
+ {
+ return FindToken( predicateData.type, predicateData.match, offset );
+ }
+
+ public Token FindToken( string type, string match, int offset = 0 )
+ {
+ return FindNode( n => n.IsToken( type, match ), offset ) as Token;
+ }
+
+
+ public Token FindToken( LexerMatcher matcher, string match, int offset = 0 )
+ {
+ return FindNode( n => n.IsToken( matcher, match ), offset ) as Token;
+ }
+
+ public int FindTokenIndex( LexerMatcher matcher, string match, int offset = 0, int end = -1, bool forward = true )
+ {
+ return FindIndex( n => n.IsToken( matcher, match ), offset, end, forward );
+ }
+
+ public int FindTokenIndex( string type, string match, int offset = 0, int end = -1, bool forward = true )
+ {
+ return FindIndex( n => n.IsToken( type, match ), offset, end, forward );
+ }
+
+ public int FindTokenIndex( LexerMatcher matcher, int offset = 0, int end = -1, bool forward = true )
+ {
+ return FindIndex( n => n.IsToken( matcher, null ), offset, end, forward );
+ }
+
+ public int ReverseFindTokenIndex( LexerMatcher matcher, int reverseOffset = 0)
+ {
+ return FindTokenIndex( matcher, -( 1 + reverseOffset ), 0, false );
+ }
+
+ public int ReverseFindTokenIndex( TokenPredicateData predicateData, int reverseOffset = 0 )
+ {
+ return FindTokenIndex( predicateData.type, predicateData.match, -( 1 + reverseOffset ), 0, false );
+ }
+
+ public Token ReverseFindToken( TokenPredicateData predicateData, int reverseOffset = 0 )
+ {
+ var index = ReverseFindTokenIndex( predicateData, reverseOffset );
+
+ return index == -1 ? null : ( children[ index ] as Token );
+ }
+
+ public List GetFilteredTokens( int offset = 0, int end = -1 )
+ {
+ var tokens = new List();
+
+ IterateTokens( tokens.Add, offset, end );
+
+ return tokens;
+ }
+
+
+
+ public void Iterate( Action action, Predicate filter = null, int offset = 0, int end = -1, bool forward = true )
+ {
+ offset = ComputeIndex( offset );
+ end = ComputeIndex( end );
+
+ int change = forward ? 1 : -1;
+ end += change;
+
+ for ( int i = offset; i != end; i += change )
+ {
+ if ( children[ i ] is T t && ( filter == null || filter( t ) ) )
+ {
+ action( t );
+ }
+ }
+
+
+ }
+
+ public void IterateTokens( Action action, int start = 0, int end = -1, LexerMatcher[] ignoreMatchers = null, bool forward = true )
+ {
+ start = ComputeIndex( start );
+ end = ComputeIndex( end );
+
+ ignoreMatchers = ignoreMatchers ?? LexerMatcherLibrary.Ignore;
+ Iterate( action, ( t ) => ! t.IsAnyTokenOf( ignoreMatchers ), start, end, true );
+ }
+
+ public string GetTokenMatches( int offset = 0, int end = -1, LexerMatcher[] ignoreMatchers = null )
+ {
+ var sb = new StringBuilder();
+
+ IterateTokens(
+ ( tk )=>
+ {
+ sb.Append( tk.match );
+ },
+ offset, end,
+ ignoreMatchers,
+ true
+ );
+
+ return sb.ToString();
+ }
+
+ public int SearchIndex( Predicate searchPredicate, Predicate ignore = null, int offset = 0, int end = -1, bool forward = true )
+ {
+ offset = ComputeIndex( offset );
+ end = ComputeIndex( end );
+
+ var change = forward ? 1 : -1;
+ end += change;
+
+ // RJLog.Log( "SearchIndex", offset, end, "Change", change );
+
+ if ( change > 0 && end < offset )
+ {
+ throw new System.Exception( "Invalid range, offset is higher than end: " + offset + " >> " + end );
+ }
+ else if ( change < 0 && end > offset )
+ {
+ throw new System.Exception( "Invalid range, offset is lower than end: " + offset + " >> " + end );
+ }
+
+ for ( int i = offset; i != end; i += change )
+ {
+ if ( searchPredicate( children[ i ] ) )
+ {
+ return i;
+ }
+
+ if ( ignore( children[ i ] ) )
+ {
+ continue;
+ }
+
+ return -1;
+ }
+
+
+ return -1;
+ }
+
+ public int SearchFilteredTokenIndex( LexerMatcher matcher, string match, int offset = 0 )
+ {
+ return SearchIndex(
+ ( n ) => n.IsToken( matcher, match ),
+ ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ),
+ offset, -1,
+ true
+ );
+ }
+
+ public int SearchFilteredTokenIndex( string type, string match, int offset = 0 )
+ {
+ return SearchIndex(
+ ( n ) => n.IsToken( type, match ),
+ ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ),
+ offset, -1,
+ true
+ );
+ }
+
+ public int SearchFilteredTokenIndex( Predicate predicate, int offset = 0 )
+ {
+ return SearchIndex(
+ ( n ) => n is Token t && predicate( t ),
+ ( n ) => n.IsAnyTokenOf( LexerMatcherLibrary.Ignore ),
+ offset, -1,
+ true
+ );
+ }
+
+ public int SearchFilteredTokenIndex( LexerMatcher matcher, int offset = 0 )
+ {
+ return SearchFilteredTokenIndex( matcher, null, offset );
+ }
+
+ public List SearchFilteredSequence( List> sequence, int offset = 0 )
+ {
+ var output = new List();
+
+ for ( int i = 0; i < sequence.Count; i++ )
+ {
+ var next = SearchFilteredTokenIndex( sequence[ i ], offset );
+
+ if ( next == -1 )
+ {
+ // RJLog.Log( "Could not find sequence step", i, "at offset", offset );
+ return null;
+ }
+
+ // RJLog.Log( "Found sequence step", i, "at offset", offset, "in", next );
+ output.Add( next );
+
+ offset = next + 1;
+ }
+
+
+ return output;
+ }
+
+ public List SearchFilteredRepeatSequence( List> start, List> sequence, List> end, int offset = 0 )
+ {
+ // RJLog.Log( "==== SearchFilteredRepeatSequence", offset );
+ var output = new List();
+
+ if ( start != null )
+ {
+ var startList = SearchFilteredSequence( start, offset );
+
+ if ( startList == null )
+ {
+ // RJLog.Log( "Start not matched", offset );
+ return null;
+ }
+
+ // RJLog.Log( "Start matched", offset );
+ output.AddRange( startList );
+
+ offset = output[ output.Count - 1 ] + 1;
+
+ // RJLog.Log( "Offset after start", offset );
+ }
+
+ if ( sequence.Count > 0 )
+ {
+ var repeatedNext = SearchFilteredSequence( sequence, offset );
+
+ if ( repeatedNext == null )
+ {
+ // RJLog.Log( "Repeat not matched", offset );
+ }
+
+ var maxSteps = 1000;
+ var steps = 0;
+
+ while ( repeatedNext != null && steps < maxSteps )
+ {
+ // RJLog.Log( "Repeat matched:",
+ // "offset", offset,
+ // "steps", steps
+ // );
+ output.AddRange( repeatedNext );
+ offset = output[ output.Count - 1 ] + 1;
+ repeatedNext = SearchFilteredSequence( sequence, offset );
+
+ steps ++;
+ }
+
+
+ // RJLog.Log( "Offset after repeat", offset );
+
+ }
+
+ if ( end != null )
+ {
+ var endList = SearchFilteredSequence( end, offset );
+
+ if ( endList == null )
+ {
+ // RJLog.Log( "End not matched", offset );
+ return null;
+ }
+
+ // RJLog.Log( "End matched", offset );
+ output.AddRange( endList );
+ }
+
+ return output;
+ }
+
+ public Token FindTriggerToken( int offset, List triggerPredicates, List blockPredicates )
+ {
+ var index = FindTriggerTokenIndex( offset, triggerPredicates, blockPredicates );
+
+ return index == -1 ? null : children[ index ] as Token;
+ }
+
+ static bool _IsInsideBlock( List counters )
+ {
+ for ( int i = 0; i < counters.Count; i++ )
+ {
+ if ( counters[ i ] > 0 )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public int FindTriggerTokenIndex( int offset, List triggerPredicates, List blockPredicates )
+ {
+ var blockTypesCounter = new List();
+ var insideBlock = false;
+
+ for ( int i = 0; i < blockPredicates.Count / 2; i++ )
+ {
+ blockTypesCounter.Add( 0 );
+ }
+
+ for ( int i = offset; i < children.Count; i++ )
+ {
+
+ var child = children[ i ];
+
+ if ( child.IsIgnoreToken() )
+ {
+ continue;
+ }
+
+
+
+ if ( ! insideBlock )
+ {
+ var triggerIndex = triggerPredicates.FindIndex( t => t.Matches( child ) );
+
+ // RJLog.Log( "Checking:", insideBlock, children[ i ], triggerIndex );
+
+ if ( triggerIndex != -1 )
+ {
+ return i;
+ }
+
+ }
+ else
+ {
+ // RJLog.Log( "Checking:", insideBlock, children[ i ] );
+ }
+
+ var blockIndex = blockPredicates.FindIndex( b => b.Matches( child ) );
+
+ if ( blockIndex == -1 )
+ {
+ continue;
+ }
+
+ var typeIndex = blockIndex / 2;
+
+ var change = typeIndex * 2 == blockIndex ? 1 : -1;
+
+ blockTypesCounter[ typeIndex ] += change;
+
+
+ insideBlock = _IsInsideBlock( blockTypesCounter );
+
+
+
+ // RJLog.Log( "bracket type:", typeIndex, "change:", change, "insideBlock:", insideBlock, "counters:", blockTypesCounter.Join( ", " ) );
+ }
+
+ return -1;
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ASTNode.cs.uid b/Runtime/Text/Parsing/AST/ASTNode.cs.uid
new file mode 100644
index 0000000..11244aa
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTNode.cs.uid
@@ -0,0 +1 @@
+uid://c2sgo6erb113h
diff --git a/Runtime/Text/Parsing/AST/ASTNodeList.cs b/Runtime/Text/Parsing/AST/ASTNodeList.cs
new file mode 100644
index 0000000..b27d055
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTNodeList.cs
@@ -0,0 +1,15 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+
+public class ASTNodeList:ASTNode
+{
+
+}
diff --git a/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid b/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid
new file mode 100644
index 0000000..a87e025
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTNodeList.cs.uid
@@ -0,0 +1 @@
+uid://b7bdp0xuww804
diff --git a/Runtime/Text/Parsing/AST/ASTWalker.cs b/Runtime/Text/Parsing/AST/ASTWalker.cs
new file mode 100644
index 0000000..a8b42e7
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTWalker.cs
@@ -0,0 +1,36 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+
+public class ASTWalker:TreeWalker
+{
+ public static readonly ASTWalker instance = new ASTWalker();
+
+ public override ASTNode Parent( ASTNode node )
+ {
+ return node?.parent;
+ }
+
+ public override ASTNode ChildAt( ASTNode node, int index )
+ {
+ if ( node == null || index < 0 || index >= node.children.Count )
+ {
+ return null;
+ }
+
+ return node.children[ index ];
+ }
+
+ public override int NumChildren( ASTNode node )
+ {
+ return node?.children.Count ?? 0;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ASTWalker.cs.uid b/Runtime/Text/Parsing/AST/ASTWalker.cs.uid
new file mode 100644
index 0000000..6af338c
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ASTWalker.cs.uid
@@ -0,0 +1 @@
+uid://dckstcta240bf
diff --git a/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs
new file mode 100644
index 0000000..55111d9
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs
@@ -0,0 +1,15 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface EnumValueDeclaration
+{
+ public string GetEnumName();
+ public string GetEnumValue();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid
new file mode 100644
index 0000000..1e3a888
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/EnumValueDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bm88qdxlr5bbl
diff --git a/Runtime/Text/Parsing/AST/ImportDeclaration.cs b/Runtime/Text/Parsing/AST/ImportDeclaration.cs
new file mode 100644
index 0000000..31d3795
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ImportDeclaration.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface ImportDeclaration
+{
+ public string GetImportPath();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid
new file mode 100644
index 0000000..e3f3bc1
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ImportDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bb50r0rlavqev
diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs
new file mode 100644
index 0000000..d0ea560
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs
@@ -0,0 +1,55 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class ASTMatchResult
+{
+ public ASTNode parent = null;
+ public int childOffset = -1;
+ public int resultStart = -1;
+ public int resultEnd = -1;
+ public bool matched = false;
+
+ public Token resultStartToken => ! matched ? null : parent.children[ resultStart ] as Token;
+ public Token resultEndToken => ! matched ? null : parent.children[ resultEnd ] as Token;
+
+ public void SetMatchedByLength( int matchLength )
+ {
+ resultStart = childOffset;
+ resultEnd = childOffset + ( matchLength - 1 );
+ matched = true;
+ }
+
+ public void SetMatched( int index, int endIndex = -1 )
+ {
+ resultStart = index;
+ resultEnd = endIndex == -1 ? index : endIndex;
+ matched = true;
+ }
+
+
+
+ public int matchLength => ( resultEnd - resultStart ) + 1;
+ public int childOffsetMatchLength => ( resultEnd - childOffset ) + 1;
+
+ public ASTMatchResult Clone()
+ {
+ var c = new ASTMatchResult();
+ c.parent = parent;
+ c.childOffset = childOffset;
+ c.resultStart = resultStart;
+ c.resultEnd = resultEnd;
+ c.matched = matched;
+
+ return c;
+ }
+
+
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid
new file mode 100644
index 0000000..6cc5ddb
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatchResult.cs.uid
@@ -0,0 +1 @@
+uid://d0oglqq8hrpqq
diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs
new file mode 100644
index 0000000..5ef5477
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs
@@ -0,0 +1,26 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public abstract class ASTMatcher
+{
+ public virtual int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var astResult = new ASTMatchResult();
+ astResult.parent = parent;
+ astResult.childOffset = childOffset;
+
+ Match( astResult );
+
+ return astResult.matched ? astResult.childOffsetMatchLength : -1;
+ }
+
+ public abstract void Match( ASTMatchResult result );
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid
new file mode 100644
index 0000000..c42cd26
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/ASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://djut8mpfu6sep
diff --git a/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs
new file mode 100644
index 0000000..98913c3
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs
@@ -0,0 +1,98 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class BracketBlockMatcher:ASTMatcher
+{
+ public TokenPredicateData blockStart;
+ public TokenPredicateData blockEnd;
+ public bool matchingAtStartIsMandatory = true;
+
+ public override void Match( ASTMatchResult result )
+ {
+ var parent = result.parent;
+ var childOffset = result.childOffset;
+
+ var count = 0;
+
+ if ( matchingAtStartIsMandatory && ! blockStart.Matches( parent.children[ childOffset ] ) )
+ {
+ return;
+ }
+
+ for ( int i = childOffset; i < parent.children.Count; i++ )
+ {
+ var child = parent.children[ i ];
+
+ if ( blockStart.Matches( child ) )
+ {
+ if ( count == 0 )
+ {
+ result.resultStart = i;
+ }
+
+ count ++;
+ }
+ else if ( blockEnd.Matches( child ) )
+ {
+ count --;
+
+ if ( count == 0 )
+ {
+ result.SetMatched( childOffset, i );
+ return;
+ }
+ }
+ else if ( count < 0 )
+ {
+ result.resultStart = -1;
+ return;
+ }
+ }
+
+ result.resultStart = -1;
+ return;
+ }
+
+ public override int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var count = 0;
+
+ if ( matchingAtStartIsMandatory && ! blockStart.Matches( parent.children[ childOffset ] ) )
+ {
+ return -1;
+ }
+
+ for ( int i = childOffset; i < parent.children.Count; i++ )
+ {
+ var child = parent.children[ i ];
+
+ if ( blockStart.Matches( child ) )
+ {
+ count ++;
+ }
+ else if ( blockEnd.Matches( child ) )
+ {
+ count --;
+
+ if ( count == 0 )
+ {
+ return ( i - childOffset + 1 );
+ }
+ }
+ else if ( count < 0 )
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid
new file mode 100644
index 0000000..8e85daf
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/BracketBlockASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://c4niejh1k1gal
diff --git a/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs
new file mode 100644
index 0000000..382c62c
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class CombinedASTMatcher:ASTMatcher
+{
+ public List matchers;
+
+ public override void Match( ASTMatchResult result )
+ {
+ var offset = result.childOffset;
+ var end = -1;
+
+ for ( int i = 0; i < matchers.Count; i++ )
+ {
+ var subResult = result.Clone();
+ subResult.childOffset = offset;
+
+ matchers[ i ].Match( subResult );
+
+ end = subResult.resultEnd;
+
+ // var matchLength = matchers[ i ].GetMatchLength( result.parent, offset );
+
+ if ( ! subResult.matched )
+ {
+ return;
+ }
+
+ offset = subResult.resultEnd + 1;
+
+ // RJLog.Log( "Matched", i, matchers[ i ], "length:", matchLength, "combinedMatch:", combinedMatchLength, "offset:", matchOffset, ">>", offset );
+ }
+
+ result.SetMatched( result.childOffset, end );
+
+ return;
+ }
+
+ public override int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var offset = childOffset;
+ var combinedMatchLength = 0;
+
+ for ( int i = 0; i < matchers.Count; i++ )
+ {
+ var matchOffset = offset;
+ var matchLength = matchers[ i ].GetMatchLength( parent, offset );
+
+ if ( matchLength == -1 )
+ {
+ return -1;
+ }
+
+ combinedMatchLength += matchLength;
+ offset += matchLength;
+
+ RJLog.Log( "Matched", i, matchers[ i ], "length:", matchLength, "combinedMatch:", combinedMatchLength, "offset:", matchOffset, ">>", offset );
+ }
+
+ return combinedMatchLength;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid
new file mode 100644
index 0000000..1f8813d
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/CombinedASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://boxrq5cfmtlat
diff --git a/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs
new file mode 100644
index 0000000..d49d7d5
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs
@@ -0,0 +1,21 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class LambdaASTMatcher:ASTMatcher
+{
+ public Action func;
+
+ public override void Match( ASTMatchResult result )
+ {
+ func( result );
+ }
+
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid
new file mode 100644
index 0000000..a524a75
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/LambdaASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://c2svke11rfs5p
diff --git a/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs
new file mode 100644
index 0000000..76a202a
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs
@@ -0,0 +1,39 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class MultiTriggerASTMatcher:ASTMatcher
+{
+ public List triggerPredicates = [];
+ public List blockPredicates = [];
+ public bool matchSticky = false;
+
+ public override void Match( ASTMatchResult result )
+ {
+ var parent = result.parent;
+ var childOffset = result.childOffset;
+
+ var triggerIndex = parent.FindTriggerTokenIndex( childOffset, triggerPredicates, blockPredicates );
+
+ if ( matchSticky && triggerIndex != childOffset )
+ {
+ return;
+ }
+
+ if ( triggerIndex == -1 )
+ {
+ return;
+ }
+
+ result.SetMatched( triggerIndex );
+
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid
new file mode 100644
index 0000000..5dbfdec
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/MultiTriggerASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://ceitlc83bl3fv
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs
new file mode 100644
index 0000000..cd79060
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs
@@ -0,0 +1,65 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class TokenRepeatSequenceASTMatcher:ASTMatcher
+{
+ public List> startSequence = [];
+ public List> repeatSequence = [];
+ public List> endSequence = [];
+
+ public override void Match( ASTMatchResult result )
+ {
+ var parent = result.parent;
+ var childOffset = result.childOffset;
+
+ var output = parent.SearchFilteredRepeatSequence( startSequence, repeatSequence, endSequence, childOffset );
+
+ if ( output == null )
+ {
+ return;
+ }
+
+ result.SetMatched( output.First(), output.Last() );
+
+ }
+
+ public override int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var output = parent.SearchFilteredRepeatSequence( startSequence, repeatSequence, endSequence, childOffset );
+
+ if ( output != null )
+ {
+ var lastOffset = output.Last();
+ // RJLog.Log( "First child:", childOffset, parent.children[ childOffset ] );
+ // RJLog.Log( "Last child:", lastOffset, parent.children[ lastOffset ] );
+
+ var num = lastOffset - childOffset + 1;
+ // RJLog.Log( "Num Matches:", num );
+
+
+ return num;
+ }
+
+ return -1;
+ }
+
+ public static TokenRepeatSequenceASTMatcher CreateWithLexer( Lexer lexer, string start, string repeat, string end )
+ {
+ var trsm = new TokenRepeatSequenceASTMatcher();
+
+ trsm.startSequence = Token.CreateLexedSequence( lexer, start );
+ trsm.repeatSequence = Token.CreateLexedSequence( lexer, repeat );
+ trsm.endSequence = Token.CreateLexedSequence( lexer, end );
+
+ return trsm;
+ }
+
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid
new file mode 100644
index 0000000..44ea7fb
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenRepeatSequenceASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://0duohxt3mrve
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs
new file mode 100644
index 0000000..cae87d3
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs
@@ -0,0 +1,44 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class TokenSequenceASTMatcher:ASTMatcher
+{
+ public List> sequence = [];
+
+ public override void Match( ASTMatchResult result )
+ {
+ var parent = result.parent;
+ var childOffset = result.childOffset;
+
+ var output = parent.SearchFilteredSequence( sequence, childOffset );
+
+ if ( output == null )
+ {
+ return;
+ }
+
+ result.SetMatched( output.First(), output.Last() );
+
+ }
+
+ public override int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var output = parent.SearchFilteredSequence( sequence, childOffset );
+
+ if ( output != null )
+ {
+ return output.Last() - childOffset + 1 ;
+ }
+
+ return -1;
+ }
+
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid
new file mode 100644
index 0000000..607c75d
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenSequenceASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://bbtojg1s1nyk3
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs
new file mode 100644
index 0000000..96482c2
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs
@@ -0,0 +1,59 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+using System;
+
+namespace Rokojori;
+
+public class TokenWordASTMatcher:ASTMatcher
+{
+ public LexerMatcher matcher;
+ public string type;
+ public string match;
+
+ public override void Match( ASTMatchResult result )
+ {
+ var parent = result.parent;
+ var searchOffset = result.childOffset;
+
+ var node = parent.children[ searchOffset ];
+
+ var resolvedType = matcher?.type ?? type;
+
+ if ( ! node.IsToken( resolvedType, match ) )
+ {
+ return;
+ }
+
+ var endIndex = parent.SearchFilteredTokenIndex( LexerMatcherLibrary.CwordMatcher, searchOffset + 1 );
+
+ if ( endIndex == -1 )
+ {
+ return;
+ }
+
+ result.SetMatched( searchOffset, endIndex );
+
+ }
+
+ public override int GetMatchLength( ASTNode parent, int childOffset )
+ {
+ var node = parent.children[ childOffset ];
+
+ var resolvedType = matcher?.type ?? type;
+
+ if ( ! node.IsToken( resolvedType, match ) )
+ {
+ return -1;
+ }
+
+ var endIndex = parent.SearchFilteredTokenIndex( LexerMatcherLibrary.CwordMatcher, childOffset + 1 );
+
+ return endIndex == -1 ? -1 : ( endIndex - childOffset + 1 );
+ }
+
+}
diff --git a/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid
new file mode 100644
index 0000000..aa3aad9
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Matchers/TokenWordASTMatcher.cs.uid
@@ -0,0 +1 @@
+uid://4mc5huqdh54k
diff --git a/Runtime/Text/Parsing/AST/MemberDeclaration.cs b/Runtime/Text/Parsing/AST/MemberDeclaration.cs
new file mode 100644
index 0000000..8e58b10
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/MemberDeclaration.cs
@@ -0,0 +1,15 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface MemberDeclaration
+{
+ public string GetMemberName();
+ public string GetMemberType();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid b/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid
new file mode 100644
index 0000000..fe1eeac
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/MemberDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://b2ny6t7p63kd5
diff --git a/Runtime/Text/Parsing/AST/NamespaceBlock.cs b/Runtime/Text/Parsing/AST/NamespaceBlock.cs
new file mode 100644
index 0000000..61eb999
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/NamespaceBlock.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface NamespaceBlock
+{
+ public string GetNamespace();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid b/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid
new file mode 100644
index 0000000..f9ea0a0
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/NamespaceBlock.cs.uid
@@ -0,0 +1 @@
+uid://blj2e4c7oid0g
diff --git a/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs
new file mode 100644
index 0000000..6b5564a
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface NamespaceDeclaration
+{
+ public string GetNamespace();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid
new file mode 100644
index 0000000..9fd6d2b
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/NamespaceDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://cxa0tcnbff0ma
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs
new file mode 100644
index 0000000..571c860
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface ClassDeclaration
+{
+ public string GetClassName();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid
new file mode 100644
index 0000000..231f452
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/ClassDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bj0nh64qu2by1
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs
new file mode 100644
index 0000000..1e5aad7
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface EnumDeclaration
+{
+ public string GetEnumName();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid
new file mode 100644
index 0000000..0f93ff7
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/EnumDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bsu314s2w3b38
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs
new file mode 100644
index 0000000..295ec4f
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface InterfaceDeclaration
+{
+ public string GetInterfaceName();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid
new file mode 100644
index 0000000..4b69256
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ObjectTypes/InterfaceDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://j8qw38s8gwe1
diff --git a/Runtime/Text/Parsing/AST/ParameterDeclaration.cs b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs
new file mode 100644
index 0000000..919f4dc
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface ParameterDeclaration
+{
+ public string GetParameterName();
+ public string GetParameterType();
+ public string GetParameterValue();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid
new file mode 100644
index 0000000..3a9f87f
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ParameterDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://ijaip1ompbed
diff --git a/Runtime/Text/Parsing/AST/ResolvableASTNode.cs b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs
new file mode 100644
index 0000000..43af084
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public interface ResolvableASTNode
+{
+ public void Resolve();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid
new file mode 100644
index 0000000..1618308
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/ResolvableASTNode.cs.uid
@@ -0,0 +1 @@
+uid://fd3sy5gl6b6
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs
new file mode 100644
index 0000000..fd3f44d
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs
@@ -0,0 +1,34 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public abstract class ASTMatcherResolver
+{
+ public ASTMatcher matcher;
+
+ // public abstract void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length );
+ public abstract int Resolve( ASTMatchResult result, ASTMatcher matcher );
+}
+
+public class ASTMatcherResolver:ASTMatcherResolver where T:ASTNode, new()
+{
+ public System.Func initializer;
+
+ // public override void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length )
+ // {
+ // var t = parent.MergeChildrenWith( start, length );
+ // initializer( t, matcher );
+ // }
+
+ public override int Resolve( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var t = result.parent.MergeChildrenWith( result.childOffset, result.childOffsetMatchLength );
+ return initializer( t, matcher );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid
new file mode 100644
index 0000000..3854e8c
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTMatcherResolver.cs.uid
@@ -0,0 +1 @@
+uid://33q46ptb0ryn
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs
new file mode 100644
index 0000000..5f2167d
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs
@@ -0,0 +1,120 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public class ASTParser
+{
+ public ASTNode root;
+ public List resolvers = [];
+
+ public int maxSteps = 1000;
+
+
+ public void Process()
+ {
+ var result = Resolve();
+
+ var steps = 0;
+
+ while ( result && steps < maxSteps)
+ {
+ RJLog.Log( "Step", steps );
+ result = Resolve();
+ steps ++;
+ }
+ }
+
+ bool Resolve()
+ {
+ var hasResult = false;
+
+ for ( int tokenOffset = 0; tokenOffset < root.children.Count; tokenOffset++ )
+ {
+ if ( root.children[ tokenOffset ].IsIgnoreToken() )
+ {
+ continue;
+ }
+
+ // RJLog.Log( "\n\n---- [ Checking node ]", root.children[ tokenOffset ], tokenOffset );
+
+ var matchResult = new ASTMatchResult();
+ matchResult.childOffset = tokenOffset;
+ matchResult.parent = root;
+
+ for ( int resolverIndex = 0; resolverIndex < resolvers.Count; resolverIndex++ )
+ {
+ var matcherResolver = resolvers[ resolverIndex ];
+ matcherResolver.matcher.Match( matchResult );
+
+ if ( ! matchResult.matched )
+ {
+ // RJLog.Log( ">>> Not Matched:", resolverIndex, matcherResolver.matcher, matcherResolver );
+
+ continue;
+ }
+
+ RJLog.Log( ">>> Matched:", resolverIndex, matcherResolver.matcher, matcherResolver );
+
+ if ( root.children[ tokenOffset ] is Token tk )
+ {
+ RJLog.Log( "...", tk.lineInfo );
+ }
+
+ var resolvedOffset = matcherResolver.Resolve( matchResult, matcherResolver.matcher );
+ tokenOffset = resolvedOffset;
+
+ hasResult = true;
+ resolverIndex = resolvers.Count;
+
+ // RJLog.Log( "Matched:", matcherIndex, matcherResolver.matcher, matcherResolver );
+ //return true;
+ }
+ }
+
+ return hasResult;
+ }
+
+ // bool ResolveOld()
+ // {
+ // var hasResult = false;
+
+ // for ( int tokenOffset = 0; tokenOffset < root.children.Count; tokenOffset++ )
+ // {
+ // if ( root.children[ tokenOffset ].IsIgnoreToken() )
+ // {
+ // continue;
+ // }
+
+ // RJLog.Log( "Checking node:", tokenOffset, root.children[ tokenOffset ] );
+
+ // for ( int matcherIndex = 0; matcherIndex < resolvers.Count; matcherIndex++ )
+ // {
+ // var matcherResolver = resolvers[ matcherIndex ];
+ // var matchLength = matcherResolver.matcher.GetMatchLength( root, tokenOffset );
+
+ // if ( matchLength == -1 )
+ // {
+
+ // continue;
+ // }
+
+ // matcherResolver.Resolve( root, matcherResolver.matcher, tokenOffset, matchLength );
+
+
+ // hasResult = true;
+
+ // RJLog.Log( "Matched:", matcherIndex, matcherResolver.matcher, matcherResolver );
+ // //return true;
+ // }
+ // }
+
+ // return hasResult;
+ // }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid
new file mode 100644
index 0000000..af341d0
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTParser.cs.uid
@@ -0,0 +1 @@
+uid://2i1vuxaa3b2w
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs
new file mode 100644
index 0000000..4ee06a9
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+public abstract class ASTResolver
+{
+ public abstract void Resolve( ASTNode parent, ASTMatcher matcher, int start, int length );
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid
new file mode 100644
index 0000000..202acf7
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Resolver/ASTResolver.cs.uid
@@ -0,0 +1 @@
+uid://dijwir0cj2lkj
diff --git a/Runtime/Text/Parsing/AST/Token.cs b/Runtime/Text/Parsing/AST/Token.cs
new file mode 100644
index 0000000..fa6893e
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Token.cs
@@ -0,0 +1,163 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+
+
+public class Token:ASTNode
+{
+ // public class PredicateData
+ // {
+ // public string type;
+ // public string match;
+
+ // public bool Matches( ASTNode node )
+ // {
+ // return node.IsToken( type, match );
+ // }
+
+ // public System.Predicate predicate
+ // {
+ // get
+ // {
+ // System.Predicate pred = ( tk ) => tk.Is( type, match );
+ // return pred;
+ // }
+ // }
+
+ // public static PredicateData Create( string type, string match = null )
+ // {
+ // var pd = new PredicateData();
+ // pd.type = type;
+ // pd.match = match;
+ // return pd;
+ // }
+
+ // public static TokenPredicateData Lexed( Lexer lexer, string value )
+ // {
+ // var lexedSequence = CreateLexedSequenceData( lexer, value );
+ // return lexedSequence[ 0 ];
+ // }
+ // }
+
+ public LexerEvent lexerEvent;
+
+ public string match => lexerEvent.match;
+ public string type => lexerEvent.type;
+
+
+ public override string ToString()
+ {
+ var matchInfo = match.Replace( "\n", "\\n" ).Replace( "\r", "\\r" );
+
+ return $"Token{{ '{matchInfo}' ({type}) }}";
+ }
+
+ public bool Is( string type, string match = null )
+ {
+ return lexerEvent.Is( type, match );
+ }
+
+ public bool Is( LexerMatcher matcher, string match = null )
+ {
+ return lexerEvent.Is( matcher.type, match );
+ }
+
+
+ ASTFileRoot _root;
+
+ public string lineInfo
+ {
+ get
+ {
+ if ( _root == null )
+ {
+ _root = ASTWalker.instance.GetInParents( this, n => n is ASTFileRoot ) as ASTFileRoot;
+ }
+
+ var textLine = _root.GetTextLinesMapper().GetLine( lexerEvent.offset );
+ return "[ " + textLine.textEditorLineIndex + " ] | " + textLine.GetContent( _root.GetSource() );
+ }
+ }
+
+ public static Token Create( LexerEvent le, ASTNode parent = null )
+ {
+ var t = new Token();
+ t.lexerEvent = le;
+ t.parent = parent;
+
+ return t;
+ }
+
+ public System.Predicate ToPredicate( Lexer lexer = null )
+ {
+ var isVariableMatch = lexer == null ? Lexer.IsVariableMatchType( type ) : lexer.HasVariableMatch( type );
+ var match = isVariableMatch ? null : this.match;
+ System.Predicate predicate = ( tk ) => tk.Is( type, match );
+ return predicate;
+ }
+
+ public TokenPredicateData ToPredicateData( Lexer lexer = null )
+ {
+ var isVariableMatch = lexer == null ? Lexer.IsVariableMatchType( type ) : lexer.HasVariableMatch( type );
+ var match = isVariableMatch ? null : this.match;
+ return TokenPredicateData.Create( type, match );
+ }
+
+
+ public static System.Predicate CreateRawPredicate( LexerMatcher matcher, string match = null )
+ {
+ System.Predicate predicate = ( tk ) => tk.Is( matcher, match );
+ return predicate;
+ }
+
+ public static List> CreateLexedSequence( Lexer lexer, string sequence )
+ {
+ lexer.Clear();
+ var lexedSequence = lexer.LexToList( sequence );
+
+ if ( lexer.hasError )
+ {
+ throw new System.Exception( "Lexer has error at char " + lexedSequence.Last().offset + " >> '" + sequence + "'" );
+ }
+
+ lexedSequence.Pop();
+ lexer.GrabMatches( lexedSequence, sequence );
+
+ var filteredEvents = lexedSequence.Filter( le => ! le.IsAnyOf( LexerMatcherLibrary.Ignore ) );
+
+ // RJLog.Log( "Creating predicates:", "'" + sequence + "'", ">", filteredEvents.Count, ">>", filteredEvents.Map( e => e.type + " : " + e.match ).Join( ", " ) );
+
+ var tokenSequence = filteredEvents.Map( le => Create( le ).ToPredicate( lexer ) );
+
+ return tokenSequence;
+ }
+
+ public static List CreateLexedSequenceData( Lexer lexer, string sequence )
+ {
+ lexer.Clear();
+ var lexedSequence = lexer.LexToList( sequence );
+
+ if ( lexer.hasError )
+ {
+ throw new System.Exception( "Lexer has error at char " + lexedSequence.Last().offset + " >> '" + sequence + "'" );
+ }
+
+ lexedSequence.Pop();
+ lexer.GrabMatches( lexedSequence, sequence );
+
+ var filteredEvents = lexedSequence.Filter( le => ! le.IsAnyOf( LexerMatcherLibrary.Ignore ) );
+
+ // RJLog.Log( "Creating predicates:", "'" + sequence + "'", ">", filteredEvents.Count, ">>", filteredEvents.Map( e => e.type + " : " + e.match ).Join( ", " ) );
+
+ var tokenSequence = filteredEvents.Map( le => Create( le ).ToPredicateData( lexer ) );
+
+ return tokenSequence;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/AST/Token.cs.uid b/Runtime/Text/Parsing/AST/Token.cs.uid
new file mode 100644
index 0000000..e110739
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/Token.cs.uid
@@ -0,0 +1 @@
+uid://cphvqqm60m3r7
diff --git a/Runtime/Text/Parsing/AST/TokenPredicateData.cs b/Runtime/Text/Parsing/AST/TokenPredicateData.cs
new file mode 100644
index 0000000..7fd1837
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/TokenPredicateData.cs
@@ -0,0 +1,45 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
+
+using System.Globalization;
+using Godot;
+
+namespace Rokojori;
+
+
+
+public class TokenPredicateData
+{
+ public string type;
+ public string match;
+
+ public bool Matches( ASTNode node )
+ {
+ return node.IsToken( type, match );
+ }
+
+ public System.Predicate predicate
+ {
+ get
+ {
+ System.Predicate pred = ( tk ) => tk.Is( type, match );
+ return pred;
+ }
+ }
+
+ public static TokenPredicateData Create( string type, string match = null )
+ {
+ var pd = new TokenPredicateData();
+ pd.type = type;
+ pd.match = match;
+ return pd;
+ }
+
+ public static TokenPredicateData Lexed( Lexer lexer, string value )
+ {
+ var lexedSequence = Token.CreateLexedSequenceData( lexer, value );
+ return lexedSequence[ 0 ];
+ }
+}
diff --git a/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid b/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid
new file mode 100644
index 0000000..ed0c756
--- /dev/null
+++ b/Runtime/Text/Parsing/AST/TokenPredicateData.cs.uid
@@ -0,0 +1 @@
+uid://ckmrtyfsdfncg
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs
new file mode 100644
index 0000000..a72d4aa
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class ExpressionContext
+{
+ public ExpressionResult result;
+ public List messages = [];
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid
new file mode 100644
index 0000000..0f6700f
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionContext.cs.uid
@@ -0,0 +1 @@
+uid://c6itj3geuk3nu
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs
new file mode 100644
index 0000000..7a3226c
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public abstract class ExpressionEvaluator
+{
+ protected virtual ExpressionContext _CreateContext(){ return new ExpressionContext(); }
+ protected abstract ExpressionResult _Evaluate( ExpressionContext context, OperatorExpression expression );
+
+ public ExpressionContext EvaluateExpression( OperatorExpression expression )
+ {
+ var context = _CreateContext();
+ context.result = _Evaluate( context, expression );
+
+ return context;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid
new file mode 100644
index 0000000..68ff8f9
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionEvaluator.cs.uid
@@ -0,0 +1 @@
+uid://bfwfkc6f5kl6o
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs
new file mode 100644
index 0000000..1bb5f6a
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class ExpressionResult
+{
+ public object value;
+ public List messages = [];
+
+ public bool hasError => messages.Find( m => m.type == MessageType.Error ) != null;
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid
new file mode 100644
index 0000000..2b9c24d
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Evaluator/ExpressionResult.cs.uid
@@ -0,0 +1 @@
+uid://isphlk2qxbbd
diff --git a/Runtime/Text/Parsing/Expressions/ExpressionParser.cs b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs
new file mode 100644
index 0000000..dbcf1f5
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class ExpressionParser:ParserPhase
+{
+ public List levels = [];
+
+ public override void Process( Parser parser )
+ {
+ ProcessExpression( parser.root );
+ }
+
+ public void ProcessExpression( ASTNode expressionParent )
+ {
+ var parser = expressionParent.parser;
+
+ for ( int i = 0; i < levels.Count; i++ )
+ {
+ var changed = levels[ i ].Process( expressionParent );
+
+ if ( parser.hasErrors )
+ {
+ return;
+ }
+
+ if ( changed )
+ {
+ i = -1;
+ }
+ }
+ }
+
+ protected PrecedenceLevel AddPrecedenceLevel( params ExpressionOperator[] operators )
+ {
+ var level = new PrecedenceLevel();
+ level.operators.AddRange( operators );
+
+ var isFromRight = operators.Find( op => ! op.IsFromLeft() ) != null;
+ level.fromLeft = ! isFromRight;
+
+ this.levels.Add( level );
+ return level;
+ }
+}
diff --git a/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid
new file mode 100644
index 0000000..283bce8
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/ExpressionParser.cs.uid
@@ -0,0 +1 @@
+uid://b21erul0athda
diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs
new file mode 100644
index 0000000..eb9654b
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface IBinaryExpression:OperatorExpression
+{
+ public void InitializeBinaryExpression( ASTNode left, ASTNode opNode, ASTNode right );
+ public ASTNode GetLeftExpression();
+ public ASTNode GetOperatorExpression();
+ public ASTNode GetRightExpression();
+}
+
+public class BinaryExpression:ASTNode,IBinaryExpression
+{
+ public ASTNode left;
+ public ASTNode op;
+ public ASTNode right;
+
+ public void InitializeBinaryExpression( ASTNode left, ASTNode op, ASTNode right )
+ {
+ this.left = left;
+ this.op = op;
+ this.right = right;
+ }
+
+ public ASTNode GetLeftExpression()
+ {
+ return left;
+ }
+
+ public ASTNode GetOperatorExpression()
+ {
+ return op;
+ }
+
+ public ASTNode GetRightExpression()
+ {
+ return right;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid
new file mode 100644
index 0000000..6811953
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryExpression.cs.uid
@@ -0,0 +1 @@
+uid://h3v0ijwgdy5a
diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs
new file mode 100644
index 0000000..90a25ef
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class BinaryOperator:ExpressionOperator where T:ASTNode,IBinaryExpression, new()
+{
+ bool _fromLeft = false;
+
+ public BinaryOperator( string symbol, bool fromLeft = true )
+ {
+ startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.OperatorMatcher.type, symbol );
+ _fromLeft = fromLeft;
+ }
+
+ public override bool IsFromLeft()
+ {
+ return _fromLeft;
+ }
+
+ public override bool ProcessStartNode( ASTNode parent, int startChildIndex )
+ {
+ var leftIndex = parent.PreviousIndex( startChildIndex );
+ var rightIndex = parent.NextIndex( startChildIndex );
+
+ if ( leftIndex < 0 || rightIndex < 0 || leftIndex >= parent.children.Count || rightIndex >= parent.children.Count )
+ {
+ parent.parser.AddError( "Could not find left/right expressions for " + this + " in parent:" + parent + " child start: " + startChildIndex );
+ return false;
+ }
+
+ var leftExpression = parent.children[ leftIndex ];
+ var rightExpression = parent.children[ rightIndex ];
+ var op = parent.children[ startChildIndex ];
+
+ var binaryExpression = parent.MergeOuter( leftIndex, rightIndex );
+ binaryExpression.InitializeBinaryExpression( leftExpression, op, rightExpression );
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid
new file mode 100644
index 0000000..a6486a1
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/BinaryOperator.cs.uid
@@ -0,0 +1 @@
+uid://buximvl87r1m2
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs
new file mode 100644
index 0000000..b39b280
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface IConstantExpression:OperatorExpression
+{
+ public void InitializeConstantExpression( ASTNode expression );
+ public ASTNode GetConstantExpression();
+}
+
+public class ConstantExpression:ASTNode,IConstantExpression
+{
+ public ASTNode constant;
+
+ public void InitializeConstantExpression( ASTNode constant )
+ {
+ this.constant = constant;
+ }
+
+ public ASTNode GetConstantExpression()
+ {
+ return constant;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid
new file mode 100644
index 0000000..ed5414a
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantExpression.cs.uid
@@ -0,0 +1 @@
+uid://caqotfege5pwp
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs
new file mode 100644
index 0000000..38456d4
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class ConstantOperator:ExpressionOperator where T:ASTNode,IConstantExpression, new()
+{
+ public ConstantOperator( TokenPredicateData predicateData )
+ {
+ startTokenPredicate = predicateData;
+ }
+
+ public override bool ProcessStartNode( ASTNode parent, int startChildIndex )
+ {
+ var ce = parent.children[ startChildIndex ];
+ var ve = parent.MergeOuter( ce, ce );
+ ve.InitializeConstantExpression( ce );
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid
new file mode 100644
index 0000000..8d12ab7
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ConstantOperator.cs.uid
@@ -0,0 +1 @@
+uid://jfvs735hl3ld
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs
new file mode 100644
index 0000000..dc5ce79
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public abstract class ExpressionOperator
+{
+ public TokenPredicateData startTokenPredicate;
+
+ public virtual bool IsFromLeft()
+ {
+ return true;
+ }
+
+ public bool IsStartNode( ASTNode node )
+ {
+ return startTokenPredicate.Matches( node );
+ }
+
+ public virtual int FindStartNodeIndex( ASTNode parent )
+ {
+ var start = IsFromLeft() ? 0 : ( parent.children.Count - 1 );
+ var end = IsFromLeft() ? parent.children.Count : -1;
+
+ var step = IsFromLeft() ? 1 : -1;
+
+ for ( int i = start; i != end; i += step )
+ {
+ if ( IsStartNode( parent.children[ i ] ) )
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public abstract bool ProcessStartNode( ASTNode parent, int startChildIndex );
+}
diff --git a/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid
new file mode 100644
index 0000000..377a09d
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/ExpressionOperator.cs.uid
@@ -0,0 +1 @@
+uid://bpa5v70lmadw7
diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs
new file mode 100644
index 0000000..bc9d237
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface IGroupExpression:OperatorExpression
+{
+ public void InitializeGroup( ASTNode left, ASTNode groupBody, ASTNode right );
+ public ASTNode GetGroupBody();
+}
+
+public class GroupExpression:ASTNode,IGroupExpression
+{
+ public ASTNode left;
+ public ASTNode groupBody;
+ public ASTNode right;
+
+
+ public void InitializeGroup( ASTNode left, ASTNode groupBody, ASTNode right )
+ {
+ this.left = left;
+ this.groupBody = groupBody;
+ this.right = right;
+ }
+
+ public ASTNode GetGroupBody()
+ {
+ return groupBody;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid
new file mode 100644
index 0000000..da6b6ef
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/GroupExpression.cs.uid
@@ -0,0 +1 @@
+uid://dxsmj25b5f13r
diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs
new file mode 100644
index 0000000..a3bba34
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class GroupOperator:ExpressionOperator where T:ASTNode,IGroupExpression, new()
+{
+ public TokenPredicateData endTokenPredicate;
+
+ public GroupOperator( string startSymbol, string endSymbol, string type = null )
+ {
+ type = type ?? LexerMatcherLibrary.BracketMatcher.type;
+
+ startTokenPredicate = TokenPredicateData.Create( type, startSymbol );
+ endTokenPredicate = TokenPredicateData.Create( type, endSymbol );
+ }
+
+ public override bool ProcessStartNode( ASTNode parent, int startChildIndex )
+ {
+ var endIndex = parent.FindBracketCloserIndex( startTokenPredicate.match, endTokenPredicate.match, startChildIndex );
+
+ if ( endIndex == -1 )
+ {
+ parent.parser.AddError( "Missing end of " + this + "in parent:" + parent + " at: " + startChildIndex );
+ return false;
+ }
+
+ var start = parent.children[ startChildIndex ];
+ var end = parent.children[ endIndex ];
+
+ var groupBodyExpression = parent.MergeInner( start, end );
+
+ var groupExpression = parent.MergeOuter( start, end );
+ groupExpression.InitializeGroup( start, groupBodyExpression, end );
+
+ var expressionParser = parent.parser.GetExpressionParser();
+
+ if ( expressionParser != null )
+ {
+ expressionParser.ProcessExpression( groupBodyExpression );
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid
new file mode 100644
index 0000000..d5ca98a
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/GroupOperator.cs.uid
@@ -0,0 +1 @@
+uid://bbylgy3f16ly
diff --git a/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs
new file mode 100644
index 0000000..80695ce
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface OperatorExpression
+{
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid
new file mode 100644
index 0000000..4857c4a
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/OperatorExpression.cs.uid
@@ -0,0 +1 @@
+uid://etmo2vwlenna
diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs
new file mode 100644
index 0000000..60d6d7b
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface IUnaryExpression:OperatorExpression
+{
+ public void InitializeUnaryExpression( ASTNode unary, ASTNode expression );
+ public ASTNode GetExpression();
+ public ASTNode GetOperator();
+}
+
+public class UnaryExpression:ASTNode,IUnaryExpression
+{
+ public ASTNode unaryOperator;
+ public ASTNode expression;
+
+ public void InitializeUnaryExpression( ASTNode unaryOperator, ASTNode expression )
+ {
+ this.unaryOperator = unaryOperator;
+ this.expression = expression;
+ }
+
+ public ASTNode GetOperator()
+ {
+ return unaryOperator;
+ }
+
+ public ASTNode GetExpression()
+ {
+ return expression;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid
new file mode 100644
index 0000000..4b4bcfb
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryExpression.cs.uid
@@ -0,0 +1 @@
+uid://denmdwmr7fq47
diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs
new file mode 100644
index 0000000..016f4f9
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs
@@ -0,0 +1,115 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class UnaryOperator:ExpressionOperator where T:ASTNode,IUnaryExpression, new()
+{
+ bool _fromLeft = false;
+ bool _isPost = false;
+ bool _checkForOperators = false;
+
+ public override bool IsFromLeft()
+ {
+ return _fromLeft;
+ }
+
+ public UnaryOperator( string symbol, bool fromLeft = true, bool post = false, bool checkForOperators = false )
+ {
+ startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.OperatorMatcher.type, symbol );
+ _fromLeft = fromLeft;
+ _isPost = post;
+ _checkForOperators = checkForOperators;
+ }
+
+ public override bool ProcessStartNode( ASTNode parent, int startChildIndex )
+ {
+ var operatorNode = parent.children[ startChildIndex ];
+ var isFirstIndex = startChildIndex == 0;
+ var isLastIndex = startChildIndex == ( parent.children.Count - 1 );
+
+ if ( _isPost && isFirstIndex )
+ {
+ parent.parser.AddError( "Missing left for " + this + "in parent:" + parent + " at child:" + startChildIndex );
+ return false;
+ }
+
+ if ( ! _isPost && isLastIndex )
+ {
+ parent.parser.AddError( "Missing right " + this + "in parent:" + parent + " at child:" + startChildIndex );
+
+ return false;
+ }
+
+ var otherNodeIndexOff = _isPost ? -1 : 1;
+ var otherNodeIndex = parent.IndexOffset( startChildIndex, otherNodeIndexOff );
+ var expressionNode = parent.children[ otherNodeIndex ];
+
+ var startNode = operatorNode;
+ var endNode = expressionNode;
+
+ if ( _isPost )
+ {
+ startNode = expressionNode;
+ endNode = operatorNode;
+ }
+
+ var uniExpression = parent.MergeOuter( startNode, endNode );
+ uniExpression.InitializeUnaryExpression( operatorNode, expressionNode );
+
+ return true;
+ }
+
+ public override int FindStartNodeIndex( ASTNode parent )
+ {
+ if ( ! _checkForOperators )
+ {
+ return base.FindStartNodeIndex( parent );
+ }
+
+ var start = IsFromLeft() ? 0 : ( parent.children.Count - 1 );
+ var end = IsFromLeft() ? parent.children.Count : -1;
+
+ var step = IsFromLeft() ? 1 : -1;
+
+ for ( int i = start; i != end; i += step )
+ {
+ if ( IsStartNode( parent.children[ i ] ) && CheckStartWithOperators( parent, i ) )
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+
+ bool CheckStartWithOperators( ASTNode parent, int index )
+ {
+ var isStartIndex = index == 0;
+
+ var isPre = ! _isPost;
+
+ if ( isPre )
+ {
+ if ( isStartIndex )
+ {
+ return true;
+ }
+
+ var nodeBefore = parent.PreviousNode( index ); // nodes[ index - 1 ];
+
+ if ( nodeBefore.IsToken( LexerMatcherLibrary.OperatorMatcher.type ) )
+ {
+ return true;
+ }
+ else
+ {
+ // console.log( "node before not a operator:", nodes[ index ], ">>", nodeBefore );
+ }
+ }
+
+ return false;
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid
new file mode 100644
index 0000000..f1365f4
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/UnaryOperator.cs.uid
@@ -0,0 +1 @@
+uid://d3puyem33kchk
diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs
new file mode 100644
index 0000000..34b110b
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public interface IVariableExpression:OperatorExpression
+{
+ public void InitializeVariableExpression( ASTNode expression );
+}
+
+public class VariableExpression:ASTNode,IVariableExpression
+{
+ public ASTNode expression;
+
+ public void InitializeVariableExpression( ASTNode expression )
+ {
+ this.expression = expression;
+ }
+
+ public ASTNode GetExpression()
+ {
+ return expression;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid
new file mode 100644
index 0000000..9b0e43e
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/VariableExpression.cs.uid
@@ -0,0 +1 @@
+uid://bkuyqglhvww16
diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs
new file mode 100644
index 0000000..611f3b1
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class VariableOperator:ExpressionOperator where T:ASTNode,IVariableExpression, new()
+{
+ public VariableOperator()
+ {
+ startTokenPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type, null );
+ }
+
+ public override bool ProcessStartNode( ASTNode parent, int startChildIndex )
+ {
+ var v = parent.children[ startChildIndex ];
+ var ve = parent.MergeOuter( v, v );
+ ve.InitializeVariableExpression( v );
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid
new file mode 100644
index 0000000..09d9bf6
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/Operators/VariableOperator.cs.uid
@@ -0,0 +1 @@
+uid://b76eexwinywf7
diff --git a/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs
new file mode 100644
index 0000000..f12ee00
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class PrecedenceLevel
+{
+ public bool fromLeft = true;
+ public List operators = [];
+
+ public bool Process( ASTNode parent )
+ {
+ SearchExpressionForOperators( parent );
+
+ if ( _operatorIndex == -1 )
+ {
+ return false;
+ }
+
+ var currentOperator = operators[ _operatorIndex ];
+
+ var changed = currentOperator.ProcessStartNode( parent, _expressionIndex );
+
+ if ( changed )
+ {
+ //console.log( "Processed", className( currentOperator ), currentOperator.tokenType, currentOperator.tokenValue );
+ }
+
+ return changed;
+ }
+
+
+ public bool HasHigherPrecedence( int i, int e )
+ {
+ return fromLeft ? i < e : i > e;
+ }
+
+ int _expressionIndex = -1;
+ int _operatorIndex = -1;
+
+
+ public void SearchExpressionForOperators( ASTNode parent )
+ {
+ _expressionIndex = fromLeft ? parent.children.Count : -1;
+ _operatorIndex = -1;
+
+ for ( int i = 0; i < operators.Count; i++ )
+ {
+ var index = operators[ i ].FindStartNodeIndex( parent );
+
+ if ( index == -1 )
+ {
+ continue;
+ }
+
+ if ( ! HasHigherPrecedence( index, this._expressionIndex ) )
+ {
+ continue;
+ }
+
+ _expressionIndex = index;
+ _operatorIndex = i;
+
+ }
+
+ }
+}
diff --git a/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid
new file mode 100644
index 0000000..fdb6fd0
--- /dev/null
+++ b/Runtime/Text/Parsing/Expressions/PrecedenceLevel.cs.uid
@@ -0,0 +1 @@
+uid://7dusnbxqom3j
diff --git a/Runtime/Text/Parsing/Parser/ASTParserPhase.cs b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs
new file mode 100644
index 0000000..b54cc04
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class ASTParserPhase:ParserPhase
+{
+ public ASTParser parserProcessor;
+
+ public ASTParserPhase( ASTParser parserProcessor )
+ {
+ this.parserProcessor = parserProcessor;
+ }
+
+ public abstract ASTNode GetParsingRoot( Parser parser );
+
+ public override void Process( Parser parser )
+ {
+ parserProcessor.root = GetParsingRoot( parser );
+ parserProcessor.Process();
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid
new file mode 100644
index 0000000..4130bde
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ASTParserPhase.cs.uid
@@ -0,0 +1 @@
+uid://6uj7v6150kcc
diff --git a/Runtime/Text/Parsing/Parser/LexerPhase.cs b/Runtime/Text/Parsing/Parser/LexerPhase.cs
new file mode 100644
index 0000000..317c138
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/LexerPhase.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class LexerPhase:ParserPhase
+{
+ public LexerPhase( Lexer lexer )
+ {
+ this.lexer = lexer;
+ }
+ public Lexer lexer;
+
+ public bool outputDebugInfo = false;
+
+ public override void Process( Parser parser )
+ {
+ parser.lexerEvents = lexer.LexToList( parser.source );
+
+ if ( lexer.hasError )
+ {
+ hasStopError = true;
+ return;
+ }
+
+ parser.lexerEvents.Pop();
+
+ lexer.GrabMatches( parser.lexerEvents, parser.source );
+
+ var root = parser.root;
+
+ parser.root.children.AddRange( parser.lexerEvents.Map( le => Token.Create( le, root ) ) );
+
+ if ( outputDebugInfo )
+ {
+ var index = 0;
+
+ RJLog.Log( "Lexer Info:", "\n" +
+ parser.lexerEvents.Map( le => "["+ ( index++ ) + "] '" + ( le.type == "Break" ? "\\n" : le.match ) + "' : " + le.type + " ("+ le.offset +")" ).Join( "\n" )
+ );
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid b/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid
new file mode 100644
index 0000000..410324c
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/LexerPhase.cs.uid
@@ -0,0 +1 @@
+uid://q6mj5ke2y7h7
diff --git a/Runtime/Text/Parsing/Parser/Parser.cs b/Runtime/Text/Parsing/Parser/Parser.cs
new file mode 100644
index 0000000..95f19b3
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/Parser.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class Parser
+{
+ public string source;
+ public List lexerEvents = [];
+ public ASTNode root;
+ public List phases = [];
+ public List messages = [];
+
+
+
+ public ParserPhase stoppedParsingPhase = null;
+
+ public virtual ExpressionParser GetExpressionParser()
+ {
+ return null;
+ }
+
+ public void Parse( string source )
+ {
+ this.source = source;
+
+ foreach ( var p in phases )
+ {
+ p.Process( this );
+
+ if ( p.hasStopError )
+ {
+ stoppedParsingPhase = p;
+ return;
+ }
+ }
+ }
+
+ bool _hasErrors = false;
+ public bool hasErrors => _hasErrors;
+
+ public void AddError( string message, params TextSelection[] textSelections )
+ {
+ AddMessage( MessageType.Error, message, textSelections );
+ }
+
+ public void AddMessage( MessageType type, string message, params TextSelection[] textSelections )
+ {
+ var pm = new ParserMessage();
+ pm.message = Message.Create( type, message );
+
+ if ( textSelections != null && textSelections.Length > 0 )
+ {
+ pm.selections.AddRange( textSelections );
+ }
+
+ messages.Add( pm );
+
+ if ( type == MessageType.Error )
+ {
+ _hasErrors = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Parser/Parser.cs.uid b/Runtime/Text/Parsing/Parser/Parser.cs.uid
new file mode 100644
index 0000000..697bc5d
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/Parser.cs.uid
@@ -0,0 +1 @@
+uid://7j0igvrgv6jp
diff --git a/Runtime/Text/Parsing/Parser/ParserMessage.cs b/Runtime/Text/Parsing/Parser/ParserMessage.cs
new file mode 100644
index 0000000..b5c69df
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ParserMessage.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class ParserMessage
+{
+ public Message message;
+ public List selections = [];
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid b/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid
new file mode 100644
index 0000000..23c412a
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ParserMessage.cs.uid
@@ -0,0 +1 @@
+uid://dci6pck0rxfu5
diff --git a/Runtime/Text/Parsing/Parser/ParserPhase.cs b/Runtime/Text/Parsing/Parser/ParserPhase.cs
new file mode 100644
index 0000000..6ab4f42
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ParserPhase.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class ParserPhase
+{
+ public abstract void Process( Parser parser );
+ public bool hasStopError = false;
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid b/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid
new file mode 100644
index 0000000..ff27537
--- /dev/null
+++ b/Runtime/Text/Parsing/Parser/ParserPhase.cs.uid
@@ -0,0 +1 @@
+uid://c663techcgo6w
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs
new file mode 100644
index 0000000..96ab705
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSParser:Parser
+{
+ public LexerPhase lexerPhase = new LexerPhase( new CSLexer() );
+ public CSPreProcessor preProcessor = new CSPreProcessor();
+ public CSRootFileParser rootPhase = new CSRootFileParser();
+
+ public CSParser( string filePath, HashSet defines = null )
+ {
+ root = CSFileRoot.Create( filePath, this );
+
+ phases =
+ [
+ lexerPhase,
+ preProcessor,
+ rootPhase
+ ];
+
+ rootPhase.preProcessorContext.defines = defines ?? new HashSet();
+
+ Parse( FilesSync.LoadUTF8( filePath ) );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid
new file mode 100644
index 0000000..d4f968e
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParser.cs.uid
@@ -0,0 +1 @@
+uid://ckn0wj4udiupw
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs
new file mode 100644
index 0000000..a0e560f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using Godot;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class CSParserTest:Node
+{
+ [Export]
+ public string defines = "a,b,c";
+
+ [Export]
+ public string formula = "";
+ [ExportToolButton( "Parse Formula" )]
+ public Callable parseFormulaButton => Callable.From(
+ ()=>
+ {
+ ParseFormula();
+ }
+ );
+
+ [Export( PropertyHint.File )]
+ public string path;
+
+ [Export]
+ public bool createGD = false;
+
+
+
+ [ExportToolButton( "Parse" )]
+ public Callable parseButton => Callable.From(
+ ()=>
+ {
+ Parse();
+ }
+ );
+
+ void Parse()
+ {
+ var defines = new HashSet();
+ defines.Add( GDScriptGenerator.GD_SCRIPT_TRANSPILING );
+
+ var parser = new CSParser( ProjectSettings.GlobalizePath( path ), defines );
+
+ var root = parser.root as CSFileRoot;
+
+ this.LogInfo( "Parsed Nodes:", root.parsedNodes.Count );
+
+
+ for ( int i = 0; i < root.parsedNodes.Count; i++ )
+ {
+ this.LogInfo( i, root.parsedNodes[ i ] );
+ }
+
+ if ( createGD )
+ {
+ CreateGDClass( root );
+ }
+ }
+
+ void CreateGDClass( CSFileRoot root )
+ {
+ var originalPath = FilePath.Absolute( root.GetFilePath() );
+
+ var converter = new GDScriptFromCSAST();
+ converter.Convert( root );
+ var gdclass = converter.gdClass;
+
+ var gdgenerator = new GDScriptGenerator();
+ gdgenerator.gdClasses = [ gdclass ];
+ gdgenerator.Generate( originalPath.parentAbsolutePath );
+
+ }
+
+ void ParseFormula()
+ {
+ var defines = this.defines.Split( "," );
+ var evaluator = new CSPreProcessorConditionalEvaluator();
+ defines.ForEach( d => evaluator.defines.Add( d ) );
+ evaluator.Parse( formula );
+
+ var result = evaluator.Evaluate();
+
+ this.LogInfo( "Result:", result );
+
+ this.LogInfo( "Context:", evaluator.context.messages );
+
+ var info = evaluator.root.CreateDebugTreeInfo();
+ this.LogInfo( "\n" + info );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid
new file mode 100644
index 0000000..296b402
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/CSParserTest.cs.uid
@@ -0,0 +1 @@
+uid://btbsqwh2k3ocl
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs
new file mode 100644
index 0000000..8535a8e
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSFileRoot:ASTNode, ASTFileRoot
+{
+ public string filePath;
+ CSParser _parser;
+ public CSParser parser => _parser;
+ public Parser GetParser()
+ {
+ return _parser;
+ }
+
+ public string GetFilePath()
+ {
+ return filePath;
+ }
+
+ public string GetSource()
+ {
+ return _parser.source;
+ }
+
+ TextLinesMapper _textLinesMapper = null;
+
+ public TextLinesMapper GetTextLinesMapper()
+ {
+ if ( _textLinesMapper == null )
+ {
+ _textLinesMapper = new TextLinesMapper();
+ _textLinesMapper.Map( GetSource() );
+ }
+
+ return _textLinesMapper;
+ }
+
+
+
+ public static CSFileRoot Create( string path, CSParser parser )
+ {
+ var root = new CSFileRoot();
+ root.filePath = path;
+ root._parser = parser;
+ return root;
+ }
+
+ public List parsedNodes = new List();
+
+ public List imports = [];
+ public CSNamespaceDeclaration namespaceDeclaration;
+ public List allMemberDeclarations = [];
+ public List blocks = [];
+ public List objectDefinitions = [];
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid
new file mode 100644
index 0000000..6dfb829
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSFileRoot.cs.uid
@@ -0,0 +1 @@
+uid://dqq08jh3q0tx5
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs
new file mode 100644
index 0000000..e0c8093
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs
@@ -0,0 +1,64 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class CSImportDeclaration: ASTNode, ImportDeclaration
+{
+ public Token usingToken;
+ public List importPath;
+ public Token end;
+
+ public string GetImportPath()
+ {
+ return importPath.Map( tk => tk.match ).Join( "" );
+ }
+
+ public override string ToString()
+ {
+ return GetType().Name + "{ using " + GetImportPath()+ "; } ";
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ var usingMR = new ASTMatcherResolver();
+
+ var sequenceMatcher = TokenRepeatSequenceASTMatcher.CreateWithLexer( new CSLexer(),
+ "using cword",".cword",";"
+ );
+
+ usingMR.matcher = sequenceMatcher;
+
+ usingMR.initializer = ( imp, matcher ) =>
+ {
+ var usingIndex = imp.FindTokenIndex( LexerMatcherLibrary.UsingMatcher );
+ var endIndex = imp.ReverseFindTokenIndex( LexerMatcherLibrary.OperatorMatcher );
+
+ RJLog.Log( "Endindex:", endIndex );
+ imp.usingToken = imp.children[ usingIndex ] as Token;
+ imp.end = imp.children[ endIndex ] as Token;
+
+ var inbetween = imp.children.Sub( usingIndex + 1, endIndex - usingIndex - 1 );
+ imp.importPath = inbetween.Filter( n => ! n.IsIgnoreToken() ).Map( n => n as Token );
+
+ RJLog.Log(
+ "INIT IMPORT:", imp.usingToken, ">>", inbetween.Join( ", " ), ">>", imp.end,
+ imp.children.Last(),
+ "path only:",imp.importPath.Join( "|| ") );
+
+ var root = imp.GetParentWithType();
+
+ if ( root == null )
+ {
+ return imp.childIndex;
+ }
+
+ root.parsedNodes.Add( imp );
+ root.imports.Add( imp );
+
+ return imp.childIndex;
+ };
+
+ return usingMR;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid
new file mode 100644
index 0000000..a81b5f8
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSImportDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bhawdwu83nael
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs
new file mode 100644
index 0000000..cbbf2de
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSNamespaceBlock: ASTNode, NamespaceBlock
+{
+ public Token namespaceToken;
+ public List namespacePath;
+ public Token blockStart;
+ public Token blockEnd;
+
+ public string GetNamespace()
+ {
+ return namespacePath.Map( tk => tk.match ).Join( "" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid
new file mode 100644
index 0000000..d404374
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceBlock.cs.uid
@@ -0,0 +1 @@
+uid://dngeubh7s682t
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs
new file mode 100644
index 0000000..9d0e81b
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSNamespaceDeclaration: ASTNode, NamespaceDeclaration
+{
+ public Token namespaceToken;
+ public List namespacePath;
+ public Token end;
+
+ public string GetNamespace()
+ {
+ return namespacePath.Map( tk => tk.match ).Join( "" );
+ }
+
+ public override string ToString()
+ {
+ return GetType().Name + "{ namespace " + GetNamespace()+ "; } ";
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ var namespaceMR = new ASTMatcherResolver();
+
+ var sequenceMatcher = TokenRepeatSequenceASTMatcher.CreateWithLexer( new CSLexer(),
+ "namespace cword",".cword",";"
+ );
+
+ namespaceMR.matcher = sequenceMatcher;
+
+ namespaceMR.initializer = ( nsd, matcher ) =>
+ {
+ var nsIndex = nsd.FindTokenIndex( LexerMatcherLibrary.NamespaceMatcher );
+ var endIndex = nsd.ReverseFindTokenIndex( LexerMatcherLibrary.OperatorMatcher );
+
+ RJLog.Log( "Endindex:", endIndex );
+ nsd.namespaceToken = nsd.children[ nsIndex ] as Token;
+ nsd.end = nsd.children[ endIndex ] as Token;
+
+ var inbetween = nsd.children.Sub( nsIndex + 1, endIndex - nsIndex - 1 );
+ nsd.namespacePath = inbetween.Filter( n => ! n.IsIgnoreToken() ).Map( n => n as Token );
+
+ RJLog.Log(
+ "INIT IMPORT:", nsd.namespaceToken, ">>", inbetween.Join( ", " ), ">>", nsd.end,
+ nsd.children.Last(),
+ "path only:",nsd.namespacePath.Join( "|| ") );
+
+ var root = nsd.GetParentWithType();
+
+ if ( root == null )
+ {
+ return nsd.childIndex;
+ }
+
+ root.parsedNodes.Add( nsd );
+ root.namespaceDeclaration = nsd;
+
+ return nsd.childIndex;
+ };
+
+ return namespaceMR;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid
new file mode 100644
index 0000000..b52ff0f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSNamespaceDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://c5j8xld75nofs
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs
new file mode 100644
index 0000000..3feb2cd
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSTypeDefinition: ASTNode
+{
+ public string GetTypeDefinition()
+ {
+ return CombinedMatch().Trim();
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid
new file mode 100644
index 0000000..aae00f5
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/CSTypeDefinition.cs.uid
@@ -0,0 +1 @@
+uid://brtto8fv57gml
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs
new file mode 100644
index 0000000..b24844d
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSEnumValueDeclaration: ASTNode, EnumDeclaration
+{
+ public Token parameterName;
+ public ASTNode parameterValue;
+
+ public void Resolve()
+ {
+ var assignmentToken = FindToken( TokenPredicateData.Lexed( new CSLexer(), "=" ) );
+
+ if ( assignmentToken != null )
+ {
+ var start = assignmentToken.childIndex + 1;
+ var length = ( children.Count - 1 ) - start;
+ parameterValue = MergeChildrenWith( start, length );
+ }
+
+
+ var last = assignmentToken == null ? children.Last() : PreviousNode( assignmentToken.childIndex );
+
+ if ( ! last.IsToken( LexerMatcherLibrary.CwordMatcher ) )
+ {
+ last = PreviousNode( last.childIndex );
+ }
+
+ parameterName = last as Token;
+
+ }
+
+
+ public string GetEnumName()
+ {
+ return parameterName.match;
+ }
+
+ public string GetEnumValue()
+ {
+ return parameterValue?.CombinedMatch().Trim();
+ }
+
+ public override string ToString()
+ {
+ return GetType().Name + " " + GetEnumName() + " ( ''" + parameterName.lineInfo + "'' ) ";
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid
new file mode 100644
index 0000000..ccc2e02
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSEnumValueDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://7jnddwcp20jd
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs
new file mode 100644
index 0000000..77e7a6a
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSFieldDeclaration: CSMemberDeclaration
+{
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid
new file mode 100644
index 0000000..3544921
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSFieldDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://00vegm6r68g8
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs
new file mode 100644
index 0000000..71cd34e
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class CSMemberDeclaration: ASTNode, MemberDeclaration
+{
+ public List attributeBrackets;
+ public List modifiers;
+ public Token memberName;
+ public CSTypeDefinition memberType;
+
+ public List GetMemberModifiers()
+ {
+ return new List();
+ }
+
+ public string GetMemberName()
+ {
+ return memberName.match;
+ }
+
+ public string GetMemberType()
+ {
+ if ( this is CSMethodMemberDeclaration mm && mm.isContructor )
+ {
+ return GetMemberName();
+ }
+
+ return memberType == null ? "void" : memberType.GetTypeDefinition();
+ }
+
+ public override string ToString()
+ {
+ return GetType().Name + " " + GetMemberType() + " " + GetMemberName() + " ( ''" + memberName.lineInfo + "'' ) ";
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid
new file mode 100644
index 0000000..f4955cd
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMemberDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bi4sl13ggdb7d
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs
new file mode 100644
index 0000000..45c2fb1
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSMethodMemberDeclaration: CSMemberDeclaration
+{
+ public bool isContructor = false;
+ public Token parametersStart;
+ public ASTNode parametersContent;
+ public Token parametersEnd;
+
+ public Token blockStart;
+ public ASTNode blockContent;
+ public Token blockEnd;
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid
new file mode 100644
index 0000000..d675a6f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSMethodMemberDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bf4bnrj5kdugb
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs
new file mode 100644
index 0000000..98cf9ef
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs
@@ -0,0 +1,60 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSParameterDeclaration: ASTNode, ParameterDeclaration
+{
+ public Token parameterName;
+ public CSTypeDefinition parameterType;
+ public ASTNode parameterValue;
+
+ public void ResolveNameAndType()
+ {
+ var assignmentToken = FindToken( TokenPredicateData.Lexed( new CSLexer(), "=" ) );
+
+ if ( assignmentToken != null )
+ {
+ var start = assignmentToken.childIndex + 1;
+ var length = ( children.Count - 1 ) - start;
+ parameterValue = MergeChildrenWith( start, length );
+ }
+
+
+ var last = assignmentToken == null ? children.Last() : PreviousNode( assignmentToken.childIndex );
+
+ if ( ! last.IsToken( LexerMatcherLibrary.CwordMatcher ) )
+ {
+ last = PreviousNode( last.childIndex );
+ }
+
+ // RJLog.Log( "parameterName:", last, children.Count, children.Map( c => "'" + c.CombinedMatch() + "'" ).Join( " " ));
+
+ parameterName = last as Token;
+
+ // RJLog.Log( "Creating type:", 0, parameterName.childIndex - 1 );
+ parameterType = MergeOuter( 0, parameterName.childIndex - 1 );
+ }
+
+
+ public string GetParameterName()
+ {
+ return parameterName.match;
+ }
+
+ public string GetParameterType()
+ {
+ return parameterType.GetTypeDefinition();
+ }
+
+ public string GetParameterValue()
+ {
+ return parameterValue?.CombinedMatch().Trim();
+ }
+
+
+ public override string ToString()
+ {
+ return GetType().Name + " " + GetParameterType() + " " + GetParameterName() + " ( ''" + parameterName.lineInfo + "'' ) ";
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid
new file mode 100644
index 0000000..82f79e6
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSParameterDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://cuw23g0pnu3md
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs
new file mode 100644
index 0000000..c79a1f4
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSPropertyDeclaration: CSMemberDeclaration
+{
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid
new file mode 100644
index 0000000..a91b589
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/MemberDeclarations/CSPropertyDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://cnomgidksu0i8
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs
new file mode 100644
index 0000000..19c2b35
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSClassDeclaration: CSObjectDeclaration, ClassDeclaration
+{
+ public string GetClassName()
+ {
+ return objectName.match;
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ return Resolver( "class" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid
new file mode 100644
index 0000000..e362a0b
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSClassDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://c4gua113a0b3a
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs
new file mode 100644
index 0000000..6f4da9b
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSEnumDeclaration: CSObjectDeclaration, EnumDeclaration
+{
+ public string GetEnumName()
+ {
+ return objectName.match;
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ return Resolver( "enum" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid
new file mode 100644
index 0000000..fe2ea3a
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSEnumDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://b1wp4j3s7wxip
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs
new file mode 100644
index 0000000..7af53d9
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSInterfaceDeclaration: CSObjectDeclaration, InterfaceDeclaration
+{
+ public string GetInterfaceName()
+ {
+ return objectName.match;
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ return Resolver( "interface" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid
new file mode 100644
index 0000000..2727499
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSInterfaceDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://bjr3hv63luv34
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs
new file mode 100644
index 0000000..5426afd
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs
@@ -0,0 +1,170 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class CSObjectDeclaration: ASTNode
+{
+ public List attributeBrackets = [];
+ public List modifiers = [];
+ public Token objectType;
+ public Token objectName;
+
+ public CSObjectDeclarationTail objectTail;
+
+ public Token blockStart;
+ public ASTNode objectBody;
+ public Token blockEnd;
+
+ public override string ToString()
+ {
+ var modsInfo = "";
+
+ if ( modifiers.Count > 0 )
+ {
+ modsInfo = modifiers.Map( m => m.match ).Join( " " ) + " ";
+ }
+
+ List atts = [];
+
+ for ( int i = 0; i < attributeBrackets.Count; i+= 2 )
+ {
+ var attRange = GrabTokenRange( attributeBrackets[ i ], attributeBrackets[ i + 1 ], false );
+
+ if ( attRange == null )
+ {
+ continue;
+ }
+
+ atts.Add( attRange.Map( a => a.match ).Join( "" ) );
+ }
+
+ var attsInfo = "";
+
+ if ( atts.Count > 0 )
+ {
+ attsInfo = atts.Join( " " ) + " ";
+
+ }
+
+ return GetType().Name + "{ " + attsInfo + modsInfo + objectType.match + " " + objectName.match + " {...} } ";
+ }
+
+ protected static ASTMatcherResolver Resolver( string objectDeclartion ) where T:CSObjectDeclaration,new()
+ {
+ var lexer = new CSLexer();
+ var objectMR = new ASTMatcherResolver();
+
+ var odPredicate = TokenPredicateData.Lexed( lexer, objectDeclartion );
+ var objectMatcher = new TokenWordASTMatcher();
+ objectMatcher.type = odPredicate.type;
+ objectMatcher.match = odPredicate.match;
+
+ var blockMatcher = new BracketBlockMatcher();
+ blockMatcher.blockStart = TokenPredicateData.Lexed( lexer, "{" );
+ blockMatcher.blockEnd = TokenPredicateData.Lexed( lexer, "}" );
+ blockMatcher.matchingAtStartIsMandatory = false;
+
+ var combinedMatcher = new CombinedASTMatcher();
+ combinedMatcher.matchers = [ objectMatcher, blockMatcher ];
+
+ objectMR.matcher = combinedMatcher;
+
+ objectMR.initializer = ( t, matcher ) =>
+ {
+ var parent = t.parent;
+ var parentIndex = parent.children.IndexOf( t );
+
+ // for ( int i = 0; i < parent.children.Count; i++ )
+ // {
+ // RJLog.Log( i, parent.children[ i ].CombinedMatch(), parent.children[ i ].parent?.GetType().Name );
+ // }
+
+ var ma = CSModifierAttributesParser.ParseReverse( parent, parentIndex );
+
+ if ( ma.modifiers.Count > 0 )
+ {
+ t.modifiers = ma.modifiers;
+ }
+
+ if ( ma.attributeBrackets.Count > 0 )
+ {
+ t.attributeBrackets = ma.attributeBrackets;
+ }
+
+ if ( t.modifiers.Count > 0 || t.attributeBrackets.Count > 0 )
+ {
+ if ( t.attributeBrackets.Count > 0 )
+ {
+ // RJLog.Log(
+ // "Has Same parent:", t.parent == t.attributeBrackets[ 0 ],
+ // "Parent", t.parent?.GetType().Name,
+ // "Atts Type:", t.attributeBrackets[ 0 ].GetType().Name,
+ // "Atts Match:", t.attributeBrackets[ 0 ].CombinedMatch(),
+ // "Atts Parent", t.attributeBrackets[ 0 ].parent?.GetType().Name
+ // );
+
+ t.ExpandToPrevious( t.attributeBrackets[ 0 ] );
+ }
+ else
+ {
+ t.ExpandToPrevious( t.modifiers[ 0 ] );
+ }
+ }
+
+ t.objectType = t.FindToken( odPredicate );
+ t.objectName = t.FindToken( LexerMatcherLibrary.CwordMatcher, t.children.IndexOf( t.objectType ) + 1 );
+
+
+
+ t.blockEnd = t.ReverseFindToken( TokenPredicateData.Lexed( lexer, "}" ) );
+ t.blockStart = t.ReverseFindBracketOpener( "{", "}", t.blockEnd.childIndex );
+
+ var afterName = t.NextNode( t.objectName.childIndex );
+
+ if ( afterName != t.blockStart )
+ {
+ t.objectTail = t.MergeInner( t.objectName, t.blockStart );
+ t.objectTail.Resolve();
+
+ }
+
+ // RJLog.Log( "BLOCK:", t.blockStart, t.blockEnd );
+ t.objectBody = t.MergeInner( t.blockStart, t.blockEnd );
+
+
+
+ // t.blockStart = t.FindToken( blockMatcher.blockStart, t.children.IndexOf( t.objectName ) + 1 );
+ // t.blockEnd = t.ReverseFindToken( blockMatcher.blockEnd );
+
+ var root = t.GetParentWithType();
+
+ if ( root == null )
+ {
+ return t.childIndex;
+ }
+
+ if ( typeof( T ) == typeof( CSEnumDeclaration ) )
+ {
+ t.objectBody.CreateSeperatedList( ",",
+ e =>
+ {
+ e.Resolve();
+ }
+ );
+ }
+ else
+ {
+ var objectParser = new CSObjectParser( t.objectBody );
+ objectParser.Process( root.parser );
+ }
+
+
+ root.parsedNodes.Add( t );
+ root.objectDefinitions.Add( t );
+
+ return t.childIndex;
+ };
+
+ return objectMR;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid
new file mode 100644
index 0000000..a8602e0
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://dng66k350e8pr
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs
new file mode 100644
index 0000000..a2c265e
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSObjectDeclarationTail: ASTNode
+{
+ public ASTNodeList genericsDeclaration;
+ public ASTNodeList inheritanceDeclaration;
+
+
+ public void Resolve()
+ {
+ var genericsStart = FindToken( TokenPredicateData.Lexed( new CSLexer(), "<" ) );
+ var colon = FindToken( TokenPredicateData.Lexed( new CSLexer(), ":" ) );
+
+ if ( genericsStart != null )
+ {
+ var length = colon == null ? children.Count : colon.childIndex;
+ genericsDeclaration = MergeChildrenWith( 0, length );
+ }
+
+ if ( colon != null )
+ {
+ var start = colon.childIndex + 1;
+ var length = ( children.Count - 1 ) - start;
+ inheritanceDeclaration = MergeChildrenWith( start, length );
+ }
+ }
+
+ public string GetExtendingObject()
+ {
+ return inheritanceDeclaration.FindToken( LexerMatcherLibrary.CwordMatcher ).match;
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid
new file mode 100644
index 0000000..82fa879
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDeclarationTail.cs.uid
@@ -0,0 +1 @@
+uid://b05a10eey26lx
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs
new file mode 100644
index 0000000..04cf4ca
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSObjectDependency
+{
+ public string name;
+ public List genericParameters;
+ public string ns;
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid
new file mode 100644
index 0000000..7e0cced
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSObjectDependency.cs.uid
@@ -0,0 +1 @@
+uid://dsip8ijfdo6hv
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs
new file mode 100644
index 0000000..416cfeb
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSStructDeclaration: CSObjectDeclaration
+{
+ public string GetStructName()
+ {
+ return objectName.match;
+ }
+
+ public static ASTMatcherResolver Resolver()
+ {
+ return Resolver( "struct" );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid
new file mode 100644
index 0000000..c80ba6d
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/ObjectDeclarations/CSStructDeclaration.cs.uid
@@ -0,0 +1 @@
+uid://byuxdfq3chm4h
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs
new file mode 100644
index 0000000..14ee2c7
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+
+public class SquareBlock:ASTNode
+{
+ public Token GetSquareStart()
+ {
+ return FindToken( LexerMatcherLibrary.BracketMatcher, "[" );
+ }
+
+ public Token GetSquareEnd()
+ {
+ return ReverseFindToken( TokenPredicateData.Create( LexerMatcherLibrary.BracketMatcher.type, "]" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid
new file mode 100644
index 0000000..fe950ec
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Nodes/SquareBlock.cs.uid
@@ -0,0 +1 @@
+uid://cw4ghe8ficgwj
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs
new file mode 100644
index 0000000..8bd00c3
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs
@@ -0,0 +1,317 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSMemberResolver:ASTMatcherResolver
+{
+ public CSMemberResolver()
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ var csLexer = new CSLexer();
+ var triggerMatcher = new MultiTriggerASTMatcher();
+ triggerMatcher.triggerPredicates =
+ [
+ TokenPredicateData.Lexed( csLexer, "(" ),
+ TokenPredicateData.Lexed( csLexer, "{" ),
+ TokenPredicateData.Lexed( csLexer, "=>" ),
+ TokenPredicateData.Lexed( csLexer, "=" ),
+ TokenPredicateData.Lexed( csLexer, ";" ),
+ ];
+
+ triggerMatcher.blockPredicates =
+ [
+ TokenPredicateData.Lexed( csLexer, "[" ),
+ TokenPredicateData.Lexed( csLexer, "]" ),
+ TokenPredicateData.Lexed( csLexer, "<" ),
+ TokenPredicateData.Lexed( csLexer, ">" )
+ ];
+
+ triggerMatcher.matchSticky = true;
+
+ matcher = triggerMatcher;
+
+ }
+
+ public override int Resolve( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var mc = ResolveDeclaration( result, matcher );
+
+ if ( mc == null )
+ {
+ return -1;
+ }
+
+
+ var parent = result.parent;
+
+ var memberStartIndex = FindMemberDefinitionStart( parent, mc.childIndex );
+
+ // RJLog.Log( "Found member:", mc.memberName, "start:", memberStartIndex, "name:", mc.childIndex );
+ var atts = CSModifierAttributesParser.ParseForward( parent, memberStartIndex - 1 );
+
+ var isConstructor = IsConstructorMethod( parent, mc );
+
+ ASTNode earliestNode = null;
+
+ if ( atts.attributeBrackets != null && atts.attributeBrackets.Count > 0 )
+ {
+ earliestNode = atts.attributeBrackets[ 0 ];
+ mc.attributeBrackets = atts.attributeBrackets;
+ }
+
+ if ( atts.modifiers != null && atts.modifiers.Count > 0 )
+ {
+ if ( earliestNode == null )
+ {
+ earliestNode = atts.modifiers[ 0 ];
+ }
+
+ mc.modifiers = atts.modifiers;
+ }
+
+ if ( ! isConstructor )
+ {
+ var typeFirstIndex = atts.nextNode.childIndex;
+ var typeLastIndex = parent.PreviousIndex( mc.childIndex );
+ var memberType = parent.MergeOuter( typeFirstIndex, typeLastIndex );
+ mc.memberType = memberType;
+
+ if ( earliestNode == null )
+ {
+ earliestNode = memberType;
+ }
+ }
+ else
+ {
+ var mm = mc as CSMethodMemberDeclaration;
+ mm.isContructor = true;
+ }
+
+ mc.ExpandToPrevious( earliestNode );
+
+ RJLog.Log( "Found member", mc.memberType?.GetTypeDefinition() ?? "(constructor)" , mc.memberName );
+
+ AddToRoot( mc );
+
+ return mc.childIndex;
+
+ }
+
+ bool IsConstructorMethod( ASTNode parent, CSMemberDeclaration md )
+ {
+ if ( ! ( md is CSMethodMemberDeclaration ) )
+ {
+ return false;
+ }
+
+ var objectRoot = parent.walker.GetParentWithType( parent ) as CSObjectDeclaration;
+
+ if ( objectRoot == null )
+ {
+ return false;
+ }
+
+ var me = md as CSMethodMemberDeclaration;
+
+ return me.GetMemberName() == objectRoot.objectName.match;
+
+ }
+
+
+ public CSMemberDeclaration ResolveDeclaration( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var token = result.resultStartToken;
+
+ if ( token.match == "(" )
+ {
+ return ResolveMethod( result, matcher );
+ }
+
+ if ( token.match == "{" )
+ {
+ return ResolveProperty( result, matcher );
+ }
+
+ if ( token.match == "=" )
+ {
+ return ResolveFieldOrProperty( result, matcher );
+ }
+
+ if ( token.match == "=>" )
+ {
+ return ResolveFieldOrProperty( result, matcher );
+ }
+
+ if ( token.match == ";" )
+ {
+ return ResolveField( result, matcher );
+ }
+
+ return null;
+ }
+
+
+ void AddToRoot( CSMemberDeclaration md )
+ {
+ var root = md.GetParentWithType();
+
+ if ( root == null )
+ {
+ return;
+ }
+
+ root.parsedNodes.Add( md );
+ root.allMemberDeclarations.Add( md );
+ }
+
+ int FindMemberDefinitionStart( ASTNode parent, int memberDeclarationIndex )
+ {
+ for ( int i = memberDeclarationIndex - 1; i >= 0; i-- )
+ {
+ var child = parent.children[ i ];
+
+ if ( child is CSMemberDeclaration || child is CSObjectDeclaration )
+ {
+ return i + 1;
+ }
+ }
+
+ return 0;
+ }
+
+ CSMethodMemberDeclaration ResolveMethod( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var parent = result.parent;
+ var parametersStart = result.resultStartToken;
+
+ var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CFunctionMatcher.type );
+ var startReverseOffsetIndex = parametersStart.reverseIndexOffset;
+
+ var name = parent.ReverseFindToken( cwordPredicate, startReverseOffsetIndex );
+
+
+ var parametersEnd = parent.FindBracketCloser( "(", ")", result.resultStart );
+
+
+
+ var blockStart = parent.FindToken( TokenPredicateData.Lexed( new CSLexer(), "{" ), parametersEnd.childIndex );
+
+
+ var blockEnd = parent.FindBracketCloser( "{", "}", blockStart.childIndex );
+
+ var memberDeclaration = parent.MergeOuter( name, blockEnd );
+ memberDeclaration.parametersStart = parametersStart;
+ memberDeclaration.parametersEnd = parametersEnd;
+
+ var hasParameterTokens = memberDeclaration.NextNode( parametersStart.childIndex ) != parametersEnd;
+
+ if ( hasParameterTokens )
+ {
+ var parametersContent = memberDeclaration.MergeInner( parametersStart, parametersEnd );
+ // RJLog.Log( "Parameters:", parametersContent.CombinedMatch() );
+
+ var info = new List();
+ parametersContent.CreateSeperatedList( ",",
+ p =>
+ {
+ p.ResolveNameAndType();
+ info.Add( p.GetParameterName() + ": " + p.GetParameterType() );
+ }
+ );
+
+ RJLog.Log( "[ Parameters for " + name.match + "() ]", info.Join( ", " ) );
+
+
+
+
+ memberDeclaration.parametersContent = parametersContent;
+ }
+ else
+ {
+ RJLog.Log( "[ No parameters:", name.match + "() ]" );
+ }
+ memberDeclaration.memberName = name;
+
+ return memberDeclaration;
+ }
+
+
+
+ CSPropertyDeclaration ResolveProperty( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var parent = result.parent;
+ var blockStart = result.resultStartToken;
+
+ var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type );
+ var name = parent.ReverseFindToken( cwordPredicate, blockStart.reverseIndexOffset );
+ var blockEnd = parent.FindBracketCloser( "{", "}", blockStart.childIndex );
+
+ var memberDeclaration = parent.MergeOuter( name, blockEnd );
+ memberDeclaration.memberName = name;
+
+ return memberDeclaration;
+ }
+
+ CSMemberDeclaration ResolveFieldOrProperty( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var csLexer = new CSLexer();
+
+ var parent = result.parent;
+ var assigner = result.resultStartToken;
+
+ var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type );
+ var name = parent.ReverseFindToken( cwordPredicate, assigner.reverseIndexOffset );
+ var end = parent.FindTriggerToken(
+ assigner.childIndex,
+ [ TokenPredicateData.Lexed( csLexer, ";" ) ],
+ [
+ TokenPredicateData.Lexed( csLexer, "(" ),
+ TokenPredicateData.Lexed( csLexer, ")" ),
+ TokenPredicateData.Lexed( csLexer, "{" ),
+ TokenPredicateData.Lexed( csLexer, "}" ),
+
+ TokenPredicateData.Lexed( csLexer, "[" ),
+ TokenPredicateData.Lexed( csLexer, "]" ),
+ TokenPredicateData.Lexed( csLexer, "<" ),
+ TokenPredicateData.Lexed( csLexer, ">" )
+ ]
+ );
+
+ var isField = assigner.match == "=";
+
+ CSMemberDeclaration memberDeclaration;
+
+ if ( isField )
+ {
+ memberDeclaration = parent.MergeOuter( name, end );
+ }
+ else
+ {
+ memberDeclaration = parent.MergeOuter( name, end );
+ }
+
+ memberDeclaration.memberName = name;
+
+ return memberDeclaration;
+ }
+
+ CSFieldDeclaration ResolveField( ASTMatchResult result, ASTMatcher matcher )
+ {
+ var parent = result.parent;
+ var closer = result.resultStartToken;
+
+ var cwordPredicate = TokenPredicateData.Create( LexerMatcherLibrary.CwordMatcher.type );
+ var closerReverseOffsetIndex = closer.reverseIndexOffset;
+ var name = parent.ReverseFindToken( cwordPredicate, closerReverseOffsetIndex );
+ var end = closer;
+
+ var memberDeclaration = parent.MergeOuter( name, end );
+ memberDeclaration.memberName = name;
+ return memberDeclaration;
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid
new file mode 100644
index 0000000..96b53b7
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSMemberResolver.cs.uid
@@ -0,0 +1 @@
+uid://cxgnt4inbrsd2
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs
new file mode 100644
index 0000000..6be3562
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs
@@ -0,0 +1,215 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Rokojori;
+
+
+public class CSModifierAttributesParser
+{
+ public static bool IsExported( List attPairs )
+ {
+ return HasAttribute( "Export", attPairs );
+ }
+
+ public static bool HasAttribute( string name, List attPairs )
+ {
+ if ( attPairs == null )
+ {
+ return false;
+ }
+
+ var atts = GetAttributes( attPairs );
+
+ return atts.IndexOf( name ) != -1;
+ }
+
+ public static List GetAttributes( List attPairs )
+ {
+ var atts = new List();
+
+ if ( attPairs == null )
+ {
+ return atts;
+ }
+
+ for ( int i = 0; i < attPairs.Count; i+= 2 )
+ {
+ var s = attPairs[ i ];
+ var e = attPairs[ i + 1 ];
+
+ var parent = s.parent;
+
+ var tokens = parent.children.Range( s.childIndex + 1, e.childIndex - 1 );
+
+ // var att = tokens.Map( t => t.CombinedMatch() ).Join( "" ).Trim();
+ // atts.Add( att );
+
+ var buffer = new ASTNodeList();
+ buffer.children = tokens;
+ buffer.children.ForEach( c => c.parent = buffer );
+
+ buffer.CreateSeperatedList( "," ,
+ ( n )=>
+ {
+ var att = n.CombinedMatch().Trim();
+ atts.Add( att );
+ // atts.Add( n.CombinedMatch().Trim() );
+ }
+ );
+
+ tokens.ForEach( c => c.parent = parent );
+ }
+
+ return atts;
+
+ }
+
+ public class Data
+ {
+ public List attributeBrackets = [];
+ public List modifiers = [];
+ public ASTNode nextNode;
+
+ public string GetAttributeValue( Token start, Token end )
+ {
+ if ( start == null || end == null )
+ {
+ return "Invalid: start == null: " + ( start == null ) + " end == null: " + ( end == null );
+ }
+
+ if ( start == end )
+ {
+ return start.CombinedMatch();
+ }
+
+ var startIndex = start.childIndex;
+ var endIndex = end.childIndex;
+
+ var sb = new StringBuilder();
+
+ sb.Append( "[" );
+
+ for ( int i = startIndex + 1; i < endIndex; i++ )
+ {
+
+ sb.Append( start.parent.children[ i ].CombinedMatch() );
+ }
+
+ sb.Append( "]" );
+
+
+ return sb.ToString();
+ }
+
+ public string GetStringInfo()
+ {
+ var sb = new StringBuilder();
+
+ for ( int i = 0; i < attributeBrackets.Count; i+=2 )
+ {
+ sb.Append( GetAttributeValue( attributeBrackets[ i ], attributeBrackets[ i + 1 ] ) );
+ }
+
+ modifiers.ForEach(
+ m =>
+ {
+ sb.Append( " " );
+ sb.Append( m.CombinedMatch() );
+ }
+ );
+
+ return sb.ToString();
+ }
+ }
+
+ public static Data ParseReverse( ASTNode parent, int offset )
+ {
+ var data = new Data();
+
+ var prevIndex = parent.PreviousIndex( offset );
+ var prev = prevIndex == -1 ? null : parent.children[ prevIndex ];
+
+ while ( prev != null && prev.IsToken( LexerMatcherLibrary.CSAccessModifierMatcher ) )
+ {
+ data.modifiers.Insert( 0, prev as Token );
+
+ prevIndex = parent.PreviousIndex( prevIndex );
+ prev = prevIndex == -1 ? null : parent.children[ prevIndex ];
+ }
+
+ while ( prev != null && prev.IsToken( LexerMatcherLibrary.BracketMatcher, "]" ) )
+ {
+ var bracketOpenerIndex = parent.ReverseFindBracketOpenerIndex( "[", "]", prevIndex );
+
+ if ( bracketOpenerIndex != -1 )
+ {
+ data.attributeBrackets.Add( parent.children[ prevIndex ] as Token );
+ data.attributeBrackets.Add( parent.children[ bracketOpenerIndex ] as Token );
+ }
+
+ prevIndex = parent.PreviousIndex( bracketOpenerIndex );
+ prev = prevIndex == -1 ? null : parent.children[ prevIndex ];
+ }
+
+ if ( data.attributeBrackets.Count > 0 )
+ {
+ data.attributeBrackets.Reverse();
+ }
+
+ return data;
+ }
+
+ public static Data ParseForward( ASTNode parent, int offset )
+ {
+ var data = new Data();
+
+ var nextIndex = parent.NextIndex( offset );
+ var next = nextIndex == -1 ? null : parent.children[ nextIndex ];
+
+ while ( next != null &&
+ (
+ next.IsToken( LexerMatcherLibrary.BracketMatcher, "[" ) ||
+ next is SquareBlock
+ )
+ )
+ {
+ var isSquareBlock = next is SquareBlock;
+
+ var bracketCloserIndex = isSquareBlock ? nextIndex : parent.FindBracketCloserIndex( "[", "]", nextIndex );
+
+ if ( bracketCloserIndex != -1 )
+ {
+ if ( isSquareBlock )
+ {
+ var sb = next as SquareBlock;
+ data.attributeBrackets.Add( sb.GetSquareStart() );
+ data.attributeBrackets.Add( sb.GetSquareEnd() );
+ }
+ else
+ {
+ data.attributeBrackets.Add( parent.children[ nextIndex ] as Token );
+ data.attributeBrackets.Add( parent.children[ bracketCloserIndex ] as Token );
+ }
+
+ }
+
+ nextIndex = parent.NextIndex( bracketCloserIndex );
+ next = nextIndex == -1 ? null : parent.children[ nextIndex ];
+
+ }
+
+ while ( next != null && next.IsToken( LexerMatcherLibrary.CSAccessModifierMatcher ) )
+ {
+ data.modifiers.Add( next as Token );
+
+ nextIndex = parent.NextIndex( nextIndex );
+ next = nextIndex == -1 ? null : parent.children[ nextIndex ];
+ }
+
+ data.nextNode = next as Token;
+
+ return data;
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid
new file mode 100644
index 0000000..e0041b7
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSModifierAttributesParser.cs.uid
@@ -0,0 +1 @@
+uid://cocfup6k7r425
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs
new file mode 100644
index 0000000..ec49e5f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+
+
+public class CSObjectParser:ASTParserPhase
+{
+ ASTNode objectRoot;
+
+ public static ASTParser CreateParser( ASTNode root )
+ {
+ var csLexer = new CSLexer();
+ var blockResolver = new ASTMatcherResolver();
+ var matcher = new BracketBlockMatcher();
+
+ matcher.blockStart = TokenPredicateData.Lexed( csLexer, "[" );
+ matcher.blockEnd = TokenPredicateData.Lexed( csLexer, "]" );
+ blockResolver.matcher = matcher;
+ blockResolver.initializer = ( sb, matcher ) => sb.childIndex;
+
+
+ List resolvers =
+ [
+ CSClassDeclaration.Resolver(),
+ CSStructDeclaration.Resolver(),
+ CSEnumDeclaration.Resolver(),
+ CSInterfaceDeclaration.Resolver(),
+
+ blockResolver,
+
+ new CSMemberResolver()
+ ];
+
+ var astParser = new ASTParser();
+ astParser.resolvers = resolvers;
+ astParser.root = root;
+ return astParser;
+ }
+
+ public CSObjectParser( ASTNode root ):base( CreateParser( root ) )
+ {
+ objectRoot = root;
+
+ RJLog.Log( "Starting object parser", root );
+ }
+
+ public override ASTNode GetParsingRoot( Parser parser )
+ { return objectRoot; }
+
+
+
+
+}
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid
new file mode 100644
index 0000000..a9d5b85
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSObjectParser.cs.uid
@@ -0,0 +1 @@
+uid://uososvnyibqx
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs
new file mode 100644
index 0000000..888776f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class CSPreProcessor:ParserPhase
+{
+ public override void Process( Parser parser )
+ {
+ var csParser = parser as CSParser;
+ var tokens = parser.root.children;
+
+ var visible = true;
+
+ var visibleEvents = new List();
+
+ var stack = new CSPreProcessorStack();
+
+ stack.defines.UnionWith( csParser.rootPhase.preProcessorContext.defines );
+
+ for ( int i = 0; i < tokens.Count; i++ )
+ {
+ var tk = tokens[ i ];
+ var match = tk.CombinedMatch();
+
+ if ( ! tk.IsToken( LexerMatcherLibrary.CInstructionMatcher ) )
+ {
+ if ( visible )
+ {
+ visibleEvents.Add( tk );
+ }
+ else
+ {
+ RJLog.Log( "Removing:", tk );
+ }
+
+ continue;
+ }
+
+ RJLog.Log( "Removing:", tk );
+
+ var type = GetPreProcessorType( match );
+
+ if ( type == 0 )
+ {
+ continue;
+ }
+
+ if ( IsDefinining( match ) )
+ {
+ var defineType = match.StartsWith( "#define" );
+ var value = match.Substring( match.IndexOf( " " ) ).Trim();
+
+ stack.ProcessDefine( value, defineType );
+ }
+ else if ( IsConditional( match ) )
+ {
+ if ( match.StartsWith( "#endif" ) )
+ {
+ stack.CloseConditionalContext();
+ }
+ else if ( match.StartsWith( "#else" ) )
+ {
+ stack.SetElseBranch();
+ }
+ else
+ {
+ if ( match.StartsWith( "#if" ) )
+ {
+ stack.OpenConditionalContext();
+ }
+
+ var condition = match.Substring( match.IndexOf( " " ) ).Trim();
+ var conditionActive = CSPreProcessorConditionalEvaluator.Evaluate( condition, stack.defines );
+
+ stack.SetConditionalContext( conditionActive );
+ }
+
+ visible = stack.GetVisibility();
+ }
+
+
+ }
+
+ parser.root.children.ForEach( c => c.parent = null );
+ parser.root.children = visibleEvents;
+ parser.root.children.ForEach( c => c.parent = parser.root );
+
+ var infos = parser.root.children.Map( le => le + "" );
+ RJLog.Log( "Filtered Events:", infos.Join( "\n" ) );
+ }
+
+ public int GetPreProcessorType( string match )
+ {
+ if ( IsConditional( match ) )
+ {
+ return 1;
+ }
+
+ if ( IsDefinining( match ) )
+ {
+ return 2;
+ }
+
+ return 0;
+ }
+
+ public bool IsConditional( string match )
+ {
+ return match.StartsWithAny( "#if", "#elif", "#else", "#endif" );
+ }
+
+ public bool IsDefinining( string match )
+ {
+ return match.StartsWithAny( "#define", "#undef" );
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid
new file mode 100644
index 0000000..6bdc277
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessor.cs.uid
@@ -0,0 +1 @@
+uid://s75c3k16outa
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs
new file mode 100644
index 0000000..b1de982
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs
@@ -0,0 +1,291 @@
+using System;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+
+public class CSPreProcessorConditionalEvaluator:Parser
+{
+ public class Root:ASTNode,ASTFileRoot
+ {
+ public string path;
+ public string GetFilePath()
+ {
+ return path;
+ }
+
+ public CSPreProcessorConditionalEvaluator evaluator;
+
+ public Parser GetParser()
+ {
+ return evaluator;
+ }
+
+ public string GetSource()
+ {
+ return evaluator.source;
+ }
+
+ public TextLinesMapper GetTextLinesMapper()
+ {
+ return evaluator.linesMapper;
+ }
+
+ }
+
+ public HashSet defines = new HashSet();
+
+ public CSPreProcessorExpressionParser expressionParser = new CSPreProcessorExpressionParser();
+
+ public override ExpressionParser GetExpressionParser()
+ {
+ return expressionParser;
+ }
+
+ public LexerPhase lexerPhase = new LexerPhase( new CSLexer() );
+
+ public TextLinesMapper linesMapper = new TextLinesMapper();
+
+ public CSPreProcessorConditionalEvaluator()
+ {
+ phases = [
+ lexerPhase,
+ expressionParser
+ ];
+
+ var root = new Root();
+ root.evaluator = this;
+
+ this.root = root;
+ }
+
+ public static bool Evaluate( string expression, HashSet defines )
+ {
+ var evaluator = new CSPreProcessorConditionalEvaluator();
+ evaluator.defines.UnionWith( defines );
+ evaluator.Parse( expression );
+
+ var result = evaluator.Evaluate();
+
+ if ( result == -1 )
+ {
+ RJLog.Error( "Result:", result, "Context:", evaluator.context.messages );
+ var info = evaluator.root.CreateDebugTreeInfo();
+ RJLog.Error( "\n" + info );
+
+ throw new Exception();
+ }
+
+ return result == 1;
+ }
+
+ public ExpressionContext context;
+
+ public int Evaluate()
+ {
+ var rootExpression = this.root.walker.FindAnyChild( this.root, c => c is OperatorExpression );
+ var ev = new CSPPEvaluator();
+ ev.defines = defines ?? ( new HashSet() );
+
+ context = ev.EvaluateExpression( rootExpression as OperatorExpression );
+ var result = context.result;
+
+ if ( result.hasError )
+ {
+ RJLog.Error( result.messages );
+ return -1;
+ }
+
+ return (bool)result.value == true ? 1 : 0;
+ }
+
+ protected class CSPPEvaluator:ExpressionEvaluator
+ {
+ public HashSet defines = new HashSet();
+
+ public class Result:ExpressionResult
+ {
+ public static Result As( bool value )
+ {
+ var r = new Result();
+ r.value = value;
+ return r;
+ }
+
+ public static Result True()
+ {
+ return As( true );
+ }
+
+ public static Result False()
+ {
+ return As( false );
+ }
+
+ public static Result Error( string message, params ExpressionResult[] extendingResults )
+ {
+ var r = new Result();
+
+ for ( int i = 0; i < extendingResults.Length; i++ )
+ {
+ r.messages.AddRange( extendingResults[ i ].messages );
+ }
+
+ r.messages.Add( Message.Error( message ) );
+
+
+ return r;
+ }
+ }
+
+ protected override ExpressionContext _CreateContext()
+ {
+ return new ExpressionContext();
+ }
+
+ protected override ExpressionResult _Evaluate( ExpressionContext context, OperatorExpression expression )
+ {
+ if ( expression == null )
+ {
+ return Result.Error( "Null expression!" );
+ }
+
+
+ context.messages.Add( Message.Info( expression.GetType().Name ) );
+
+ if ( expression is ConstantExpression ce )
+ {
+ return _Eval( context, ce );
+ }
+ else if ( expression is VariableExpression ve )
+ {
+ return _Eval( context, ve );
+ }
+ else if ( expression is BinaryExpression bi )
+ {
+ return _Eval( context, bi );
+ }
+ else if ( expression is UnaryExpression un )
+ {
+ return _Eval( context, un );
+ }
+ else if ( expression is GroupExpression gr )
+ {
+ return _Eval( context, gr );
+ }
+
+ return Result.Error( "Unknown expression type: " + expression.GetType().Name );
+ }
+
+ protected ExpressionResult _Eval( ExpressionContext context, ConstantExpression expression )
+ {
+ var constant = expression.GetConstantExpression();
+
+ if ( constant.IsToken( LexerMatcherLibrary.BoolMatcher, "true" ) )
+ {
+ return Result.True();
+ }
+ else if ( constant.IsToken( LexerMatcherLibrary.BoolMatcher, "false" ) )
+ {
+ return Result.False();
+ }
+
+ return Result.Error( "Unexpected token:" + expression );
+
+ }
+
+ protected ExpressionResult _Eval( ExpressionContext context, VariableExpression expression )
+ {
+ var variableName = expression.GetExpression().CombinedMatch();
+ return Result.As( defines.Contains( variableName ) );
+ }
+
+ protected ExpressionResult _Eval( ExpressionContext context, BinaryExpression expression )
+ {
+ var left = expression.GetLeftExpression() as OperatorExpression;
+ var right = expression.GetRightExpression() as OperatorExpression;
+
+ if ( left == null )
+ {
+ RJLog.Log( "left is null:", expression.GetLeftExpression() );
+ }
+
+ if ( right == null )
+ {
+ RJLog.Log( "right is null:", expression.GetLeftExpression() );
+ }
+
+ var op = expression.GetOperatorExpression().CombinedMatch();
+
+ var leftResult = _Evaluate( context, left );
+ var rightResult = _Evaluate( context, right );
+
+ if ( leftResult.hasError || rightResult.hasError )
+ {
+ return Result.Error( "Has error: " + leftResult + " " + rightResult, leftResult, rightResult );
+ }
+
+
+ if ( op == "==" )
+ {
+ return Result.As( leftResult.value == rightResult.value );
+ }
+
+ else if ( op == "!=" )
+ {
+ return Result.As( leftResult.value != rightResult.value );
+ }
+
+ else if ( op == "&&" )
+ {
+ return Result.As( (bool)leftResult.value && (bool)rightResult.value );
+ }
+
+ else if ( op == "||" )
+ {
+ return Result.As( (bool)leftResult.value || (bool)rightResult.value );
+ }
+
+ return Result.Error( "Unknown operator: " + op );
+
+ }
+
+ protected ExpressionResult _Eval( ExpressionContext context, UnaryExpression expression )
+ {
+ var exp = expression.GetExpression() as OperatorExpression;
+
+ if ( exp == null )
+ {
+ RJLog.Log( "exp is null:", expression.GetExpression() );
+ }
+
+ var value = _Evaluate( context, exp );
+
+ if ( value.hasError )
+ {
+ return Result.Error( "Has error:" + value, value );
+ }
+
+ return Result.As( ! ( (bool)value.value ) );
+ }
+
+ protected ExpressionResult _Eval( ExpressionContext context, GroupExpression expression )
+ {
+ var gb = expression.GetGroupBody();
+
+ var exp = gb.walker.FindDirectChild( gb, c => c is OperatorExpression ) as OperatorExpression;
+
+ var value = _Evaluate( context, exp );
+
+ if ( value.hasError )
+ {
+ return Result.Error( "Has error:" + value, value );
+ }
+
+ return Result.As( (bool)value.value );
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid
new file mode 100644
index 0000000..131da98
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorConditionalEvaluator.cs.uid
@@ -0,0 +1 @@
+uid://bi7vo4gjed31l
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs
new file mode 100644
index 0000000..4a2fad0
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSPreProcessorContext
+{
+ public HashSet defines = new HashSet();
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid
new file mode 100644
index 0000000..51df0ec
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorContext.cs.uid
@@ -0,0 +1 @@
+uid://fmbkq7fn2mhf
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs
new file mode 100644
index 0000000..48b0449
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+
+public class CSPreProcessorExpressionParser:ExpressionParser
+{
+
+ public ConstantOperator boolConstantOperator;
+
+ public GroupOperator groupOperator;
+
+ public VariableOperator variableOperator;
+
+ public BinaryOperator andOperator;
+ public BinaryOperator orOperator;
+
+ public BinaryOperator equalsOperator;
+ public BinaryOperator notEqualsOperator;
+
+ public UnaryOperator notOperator;
+
+ public CSPreProcessorExpressionParser()
+ {
+ Initialize();
+ }
+
+ public void Initialize()
+ {
+ boolConstantOperator = new ConstantOperator(
+ TokenPredicateData.Create( LexerMatcherLibrary.BoolMatcher.type )
+ );
+
+ groupOperator = new GroupOperator( "(", ")" );
+
+ variableOperator = new VariableOperator();
+
+ andOperator = new BinaryOperator( "&&" );
+ orOperator = new BinaryOperator( "||" );
+
+ equalsOperator = new BinaryOperator( "==" );
+ notEqualsOperator = new BinaryOperator( "!=" );
+
+ notOperator = new UnaryOperator( "!" );
+
+
+ levels = [];
+
+ AddPrecedenceLevel( boolConstantOperator );
+
+ AddPrecedenceLevel( groupOperator );
+
+ AddPrecedenceLevel( variableOperator );
+
+ AddPrecedenceLevel( notOperator );
+
+ AddPrecedenceLevel( equalsOperator, notEqualsOperator );
+
+ AddPrecedenceLevel( andOperator );
+
+ AddPrecedenceLevel( orOperator );
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid
new file mode 100644
index 0000000..5735328
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorExpressionParser.cs.uid
@@ -0,0 +1 @@
+uid://bh4c4giiq32hk
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs
new file mode 100644
index 0000000..0a9e722
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+public class CSPreProcessorConditionalContext
+{
+ public bool lastWasTrue = false;
+}
+
+public class CSPreProcessorStack
+{
+ public HashSet defines = new HashSet();
+ public List conditionalContexts = [];
+
+ public void Push( string value )
+ {
+ defines.Add( value );
+ }
+
+ public void Pop( string value )
+ {
+ defines.Remove( value );
+ }
+
+ public void ProcessDefine( string value, bool push )
+ {
+ if ( push )
+ {
+ Push( value );
+ }
+ else
+ {
+ Pop( value );
+ }
+ }
+
+ public void OpenConditionalContext()
+ {
+ conditionalContexts.Add( new CSPreProcessorConditionalContext() );
+ }
+
+ public void CloseConditionalContext()
+ {
+ conditionalContexts.Pop();
+ }
+
+ public void SetConditionalContext( bool value )
+ {
+ conditionalContexts.Last().lastWasTrue = value;
+ }
+
+ public void SetElseBranch()
+ {
+ conditionalContexts.Last().lastWasTrue = ! conditionalContexts.Last().lastWasTrue;
+ }
+
+ public bool GetVisibility()
+ {
+ return conditionalContexts.Count == 0 || conditionalContexts.Last().lastWasTrue;
+ }
+}
+
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid
new file mode 100644
index 0000000..10c3b8d
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSPreProcessor/CSPreProcessorStack.cs.uid
@@ -0,0 +1 @@
+uid://bfkjft2gy8yqy
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs
new file mode 100644
index 0000000..e5bab43
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CSRootFileParser:ASTParserPhase
+{
+ public CSPreProcessorContext preProcessorContext = new CSPreProcessorContext();
+
+ public static ASTParser CreateParser()
+ {
+ List resolvers =
+ [
+ CSImportDeclaration.Resolver(),
+ CSNamespaceDeclaration.Resolver(),
+
+ CSClassDeclaration.Resolver(),
+ CSStructDeclaration.Resolver(),
+ CSEnumDeclaration.Resolver(),
+ CSInterfaceDeclaration.Resolver()
+ ];
+
+ var astParser = new ASTParser();
+ astParser.resolvers = resolvers;
+
+ return astParser;
+ }
+
+ public CSRootFileParser():base( CreateParser() )
+ {}
+
+ public override ASTNode GetParsingRoot( Parser p )
+ {
+ return p.root;
+ }
+
+
+}
\ No newline at end of file
diff --git a/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid
new file mode 100644
index 0000000..dec278f
--- /dev/null
+++ b/Runtime/Text/Parsing/ParserLibrary/CSharp/Parsers/CSRootFileParser.cs.uid
@@ -0,0 +1 @@
+uid://ciibe6tecx4h6
diff --git a/Runtime/Text/Text.cs b/Runtime/Text/Text.cs
index c584cd3..1212e2a 100644
--- a/Runtime/Text/Text.cs
+++ b/Runtime/Text/Text.cs
@@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
+using System.Text;
using System.Text.RegularExpressions;
@@ -8,6 +9,23 @@ namespace Rokojori
{
public static class Text
{
+ public static string Repeat( this string text, int times )
+ {
+ if ( times <= 0 )
+ {
+ return "";
+ }
+
+ var sb = new StringBuilder();
+
+ for ( int i = 0; i < times; i++ )
+ {
+ sb.Append( text );
+ }
+
+ return sb.ToString();
+ }
+
public static string GetInnerMatch( this string text, string start, string ending, int offset = 0)
{
var startIndex = text.IndexOf( start, offset );
@@ -133,6 +151,19 @@ namespace Rokojori
return long.Parse( source );
}
+ public static bool StartsWithAny( this string source, params string[] starts )
+ {
+ for ( int i = 0; i < starts.Length; i++ )
+ {
+ if ( source.StartsWith( starts[ i ] ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public static string ReplaceStart( this string source, string start, string replacement = "" )
{
if ( start == "" )
diff --git a/Runtime/Tools/Lists.cs b/Runtime/Tools/Lists.cs
index 1a060e0..a59e3ad 100644
--- a/Runtime/Tools/Lists.cs
+++ b/Runtime/Tools/Lists.cs
@@ -502,6 +502,11 @@ namespace Rokojori
return list == null ? 0 : list.Count;
}
+ public static List Range( this List elements, int start, int end )
+ {
+ return elements.Sub( start, end - start + 1 );
+ }
+
public static List Sub( this List elements, int start, int length = 0 )
{
var end = length == 0 ? elements.Count : ( start + length );
@@ -611,7 +616,12 @@ namespace Rokojori
return PopLast( list );
}
- public static T Shift( this List list )
+ public static void Prepend( this List list, List other )
+ {
+ list.InsertRange( 0, other );
+ }
+
+ public static T Shift( this List list )
{
if ( list.Count == 0 ){ return default(T); }
@@ -644,6 +654,16 @@ namespace Rokojori
return GetLast( list );
}
+ public static T GetFirst