1- using System . Linq ;
2- using System . Reflection ;
1+ using System . Reflection ;
2+ using System . Runtime . Loader ;
33using static EZCodeLanguage . Parser ;
44
55namespace EZCodeLanguage
@@ -103,9 +103,9 @@ public Interpreter(Parser parser, Debug.Breakpoint[]? breakpoints = null)
103103 private object ? returned = null ;
104104 private DataType ? Returning = null ;
105105 private int StackNumber = 0 ;
106+ internal bool hasexited = false ;
107+ public CustomAssemblyLoadContext [ ] LoadedAssemblies = [ ] ;
106108 public Stack < string > StackTrace { get ; private set ; }
107- internal record Library ( string name , string [ ] files ) ;
108- internal List < Library > DllLibraries { get ; set ; } = [ ] ;
109109 public Exception [ ] Errors { get ; private set ; } = [ ] ;
110110 public Var [ ] Vars { get ; set ; } = [ ] ;
111111 public Method [ ] Methods { get ; set ; } = [ ] ;
@@ -123,6 +123,12 @@ public void Interperate(LineWithTokens[] LineTokens)
123123 if ( Methods . Any ( x => x . Name . ToLower ( ) == "start" ) && ! StartMethodEntry )
124124 {
125125 StartMethodEntry = true ;
126+ LineWithTokens [ ] lines_with_include = LineTokens . Where ( x => x . Tokens . Length > 1 ) . Where ( x => x . Tokens [ 0 ] . Type == TokenType . Include ) . ToArray ( ) ;
127+ LineWithTokens [ ] lines_with_exclude = LineTokens . Where ( x => x . Tokens . Length > 1 ) . Where ( x => x . Tokens [ 0 ] . Type == TokenType . Exclude ) . ToArray ( ) ;
128+ if ( lines_with_include . Length > 0 )
129+ Interperate ( lines_with_include ) ;
130+ if ( lines_with_exclude . Length > 0 )
131+ Interperate ( lines_with_exclude ) ;
126132 LineWithTokens [ ] lines_with_global = LineTokens . Where ( x => x . Tokens . Length > 1 ) . Where ( x => x . Tokens [ 0 ] . Type == TokenType . Global ) . ToArray ( ) ;
127133 if ( lines_with_global . Length > 0 )
128134 Interperate ( lines_with_global ) ;
@@ -131,8 +137,9 @@ public void Interperate(LineWithTokens[] LineTokens)
131137 }
132138 else
133139 {
134- foreach ( LineWithTokens line in LineTokens )
140+ foreach ( LineWithTokens line in LineTokens )
135141 {
142+ if ( hasexited ) break ;
136143 if ( line . Tokens . Length == 0 || ( line . Tokens . Length == 1 && line . Tokens [ 0 ] . Value is Class or Method ) )
137144 continue ;
138145
@@ -158,6 +165,18 @@ public void Interperate(LineWithTokens[] LineTokens)
158165 }
159166 }
160167
168+ // Unload each assembly
169+ foreach ( var assembly in LoadedAssemblies )
170+ {
171+ assembly . Unload ( ) ;
172+ }
173+ // Let the garbage collector collect to ensure assemblies are fully unloaded
174+ for ( int i = 0 ; i < 3 ; i ++ )
175+ {
176+ GC . Collect ( ) ;
177+ GC . WaitForPendingFinalizers ( ) ;
178+ }
179+ // Exclude every package
161180 Package . RemoveAllPackagesFromExecutionDirectory ( AppDomain . CurrentDomain . BaseDirectory ) ;
162181 }
163182 internal object ? SingleLine ( LineWithTokens line )
@@ -187,29 +206,24 @@ public void Interperate(LineWithTokens[] LineTokens)
187206 string combined_packages = string . Join ( " " , line . Tokens . Skip ( 1 ) . Select ( x => x . StringValue ) ) ;
188207 string [ ] packages = combined_packages . Split ( "," ) . Select ( x=> x . Trim ( ) ) . ToArray ( ) ;
189208 Project [ ] projects = new Project [ packages . Length ] ;
209+ bool include = FirstToken . StringValue == "include" ;
190210
191211 for ( int i = 0 ; i < packages . Length ; i ++ )
192212 projects [ i ] = Package . GetPackageAsProject ( packages [ i ] ) ;
193213
194- if ( projects . Any ( x => ! string . IsNullOrEmpty ( x . LibraryDirectory ) ) )
214+ if ( projects . Any ( x => ! string . IsNullOrEmpty ( x . Configuration ? . LibraryDirectory ) ) )
195215 {
196216 string destination = AppDomain . CurrentDomain . BaseDirectory ;
197217 foreach ( var project in projects )
198218 {
199- if ( FirstToken . StringValue == "include" )
200- {
201- Package . AddPackageToExecutionDirectory ( project , destination , out var files ) ;
202- DllLibraries . Add ( new Library ( project . Name , files ) ) ;
203- }
219+ if ( include )
220+ Package . AddPackageToExecutionDirectory ( project , destination ) ;
204221 else
205- {
206- var library = DllLibraries . FirstOrDefault ( x => x . name == project . Name ) ;
207- Package . RemovePackageFromExecutionDirectory ( library . files ) ;
208- }
222+ Package . RemovePackageFromExecutionDirectory ( project , destination ) ;
209223 }
210224 }
211225
212- if ( FirstToken . StringValue == " include" )
226+ if ( include )
213227 {
214228 parser = Package . ReturnParserWithPackages ( parser , packages ) ;
215229 Methods = [ .. Methods , .. parser . Methods ] ;
@@ -429,7 +443,10 @@ public void Interperate(LineWithTokens[] LineTokens)
429443 break ;
430444
431445 case IdentType . Method :
432- Method method = ( type is Method m ) ? new Method ( m . Name , m . Line , m . Settings , m . Lines . Select ( x => new LineWithTokens ( x . Tokens . Select ( y => new Token ( y . Type , y . Value , y . StringValue ) ) . ToArray ( ) , x . Line ) ) . ToArray ( ) , m . Parameters , m . Returns ) : null ;
446+ Method method = ( type is Method m ) ?
447+ new Method ( m . Name , m . Line , m . Settings , m . Lines . Select (
448+ x => new LineWithTokens ( x . Tokens . Select ( y => new Token (
449+ y . Type , y . Value , y . StringValue ) ) . ToArray ( ) , x . Line ) ) . ToArray ( ) , m . Parameters , m . Returns ) ! : new Method ( ) ;
433450
434451 Method . MethodSettings settings = method . Settings ;
435452 bool nocol = ( settings & Method . MethodSettings . NoCol ) != 0 ;
@@ -571,6 +588,20 @@ public void Interperate(LineWithTokens[] LineTokens)
571588 throw new Exception ( $ "Error with \" undefined\" , Error Message:\" { ex . Message } \" ") ;
572589 }
573590 break ;
591+ case TokenType . Throw :
592+ string err_message = "" ;
593+ try
594+ {
595+ line . Tokens = line . Tokens . Skip ( 1 ) . Prepend ( new Token ( TokenType . Return , "return" , "return" ) ) . ToArray ( ) ;
596+ err_message = SingleLine ( line ) . ToString ( ) ;
597+ }
598+ catch ( Exception ex )
599+ {
600+ throw new Exception ( $ "Error with \" throw\" , Error Message:\" { ex . Message } \" ") ;
601+ }
602+ if ( err_message != "" )
603+ throw new Exception ( err_message ) ;
604+ break ;
574605 case TokenType . Return :
575606 try
576607 {
@@ -797,6 +828,7 @@ public void Interperate(LineWithTokens[] LineTokens)
797828 {
798829 result = SingleLine ( new LineWithTokens ( line ) ) ;
799830
831+ if ( hasexited ) break ;
800832 if ( yielded )
801833 {
802834 yielded = false ;
@@ -930,6 +962,7 @@ private IdentType IsType(string token, out object? type)
930962 {
931963 result = SingleLine ( line ) ;
932964
965+ if ( hasexited ) break ;
933966 if ( line . Tokens . Length > 0 && line . Tokens [ 0 ] . Type == TokenType . Return || returned != null )
934967 break ;
935968 }
@@ -1297,32 +1330,39 @@ public object Reflect(CSharpMethod method)
12971330 method = o [ 0 ] as CSharpMethod ;
12981331 }
12991332
1300- return InvokeMethod ( method . Path , method . Params != null ? method . Params . Select ( x => x ) . ToArray ( ) : [ ] , EZHelp ) ;
1333+ object val = InvokeMethod ( method . Path , method . Params != null ? method . Params . Select ( x => x ) . ToArray ( ) : [ ] , EZHelp , out var assembly ) ;
1334+ LoadedAssemblies = LoadedAssemblies . Append ( assembly ) . Where ( x => x != null ) . Distinct ( ) . ToArray ( ) ;
1335+
1336+ return val ;
13011337 }
1302- public static object ? InvokeMethod ( string methodPath , object [ ] parameters , EZHelp e )
1338+ public static object ? InvokeMethod ( string methodPath , object [ ] parameters , EZHelp e , out CustomAssemblyLoadContext ? assemblyContext )
13031339 {
1340+ assemblyContext = null ;
13041341 // Split the method files into type and method name
13051342 string [ ] pathParts = methodPath . Split ( '.' ) ;
13061343 if ( pathParts . Length < 2 )
13071344 {
13081345 throw new ArgumentException ( "Invalid method path" ) ;
13091346 }
1310-
13111347 if ( pathParts . Length >= 2 && pathParts [ 1 ] . Equals ( "dll" ) )
13121348 {
1313- // If the method files contains an assembly name, load the assembly
1349+ // If the method path contains an assemblyContext name, load the assemblyContext
13141350 string assemblyPath = pathParts [ 0 ] + "." + pathParts [ 1 ] ;
1315- string subdirectory = Package . LibraryDirName ; // Name of the subdirectory is first part of namespace
1316- string fullAssemblyPath = Path . Combine ( subdirectory , assemblyPath ) ; // Combine subdirectory files with assembly name
1317- Assembly assembly = Assembly . LoadFrom ( fullAssemblyPath ) ;
1351+ string subdirectory = pathParts [ 0 ] ; // Name of the subdirectory is first part of namespace
1352+ string relativeAssemblyPath = Path . Combine ( subdirectory , assemblyPath ) ; // Combine subdirectory path with assemblyContext name
1353+ string fullAssemblyPath = Path . GetFullPath ( relativeAssemblyPath ) ; // Get the absolute path of the assembly
1354+
1355+ // Get Assemblies
1356+ assemblyContext = new CustomAssemblyLoadContext ( ) ;
1357+ Assembly assembly = assemblyContext . LoadFromAssemblyPath ( fullAssemblyPath ) ;
13181358
13191359 // Get the type name
13201360 string typeName = string . Join ( "." , pathParts . Skip ( 2 ) . Take ( pathParts . Length - 3 ) ) ;
1321-
1361+
13221362 // Get the method name
13231363 string methodName = pathParts . Last ( ) ;
13241364
1325- // Get the type from the assembly
1365+ // Get the type from the assemblyContext
13261366 Type type = assembly . GetType ( typeName ) ;
13271367 if ( type == null )
13281368 {
@@ -1357,7 +1397,7 @@ public object Reflect(CSharpMethod method)
13571397 {
13581398 // Get the type from the full type name
13591399 string typeName = string . Join ( "." , pathParts . Take ( pathParts . Length - 1 ) ) ;
1360- // Include the assembly information for types in the System namespace
1400+ // Include the assemblyContext information for types in the System namespace
13611401 if ( typeName . StartsWith ( "System." ) )
13621402 {
13631403 typeName += ", mscorlib" ;
@@ -1405,5 +1445,17 @@ public object Reflect(CSharpMethod method)
14051445 }
14061446 }
14071447 }
1448+ public class CustomAssemblyLoadContext : AssemblyLoadContext
1449+ {
1450+ public CustomAssemblyLoadContext ( ) : base ( isCollectible : true )
1451+ {
1452+ }
1453+
1454+ protected override Assembly Load ( AssemblyName assemblyName )
1455+ {
1456+ // Implement if needed: load dependencies, etc.
1457+ return null ;
1458+ }
1459+ }
14081460 }
14091461}
0 commit comments