- Jon Anderson and Chris Squire
#===============================================================================================
# Example Script: SelfModifyingCode
# Demonstrates the use of dynamic code generation with Interpret, CompileMethod and LoadModule
# methods in the Script class.
#===============================================================================================
# Method metadata for the dynamic methods that will get set within the method.
data<Method> DynamicMethodMetadata
data<Method> DynamicMethodMetadataPost
# Main method which is the entry point for the script.
method Main()
{
data<Base> MyBase
data<ClassA> MyClassA = new<ClassA>
data<ClassB> MyClassB = new<ClassB>
# Must call the dynamic methods to set the global method metadata references.
DynamicMethod()
DynamicMethodPost()
# Call the virtual methods for ClassA and ClassB.
MyClassA.PrintName()
MyClassB.PrintName() # Will write out 'ClassA' since virtual method not overridden.
#----------------------------------------------------------------------
# Dynamically compile a new module (in a string) that contains ClassC
# and adds a new virtual method to ClassB.
#----------------------------------------------------------------------
GetScript().LoadModule(NewModuleCode)
# Compile new method code that references the new ClassC and then execute it.
GetScript().CompileMethod(DynamicMethodMetadata,NewMethodCode)
DynamicMethod()
# We can access the dynamically created ClassC directly using Interpret. Dynamically compiles and executes the code to create a ClassC object and return its reference.
MyBase = GetScript().InterpretRef("new<ClassC>")
# Compile new method code that references the new ClassC via a dynamically set "MyBase" and then execute it.
GetScript().CompileMethod(DynamicMethodMetadataPost,NewMethodCodePost)
DynamicMethodPost(MyBase)
# Finally, call the virtual methods for ClassA and ClassB again.
MyClassA.PrintName()
MyClassB.PrintName() # Will now write out 'ClassB' since virtual method has been added.
}
#--------------------------------------------------------------------------------------------
# Code to be compiled at run-time for demonstration purposes. NewModule adds a new ClassC
# and also adds a method to ClassB. NewMethod creates an object of type ClassC and uses it.
#--------------------------------------------------------------------------------------------
data<string> NewModuleCode = "public class ClassC from<ClassB> " + string.LF +
"{ public method virtual PrintName() { StdIO.Write('ClassC') } }" + string.LF +
"public class satellite ClassB " + string.LF +
"{ public method virtual PrintName() { StdIO.Write('ClassB') } }"
data<string> NewMethodCode = "data<ClassC> MyClassC = new<ClassC> " + string.LF +
"MyClassC.PrintName()"
data<string> NewMethodCodePost = "if ( (MyBase != null) & (MyBase is type<ClassC>) )" + string.LF +
"{ data<ClassC> MyClassC = MyBase as type<ClassC> " + string.LF +
"MyClassC.PrintName() }"
#------------------------------------------------------------------------
# Dynamic methods to be modified at run-time to access new ClassC. The
# initial code is also critical since it sets method metadata for later
# use with dynamic code generation.
#------------------------------------------------------------------------
method dynamic DynamicMethod()
{
DynamicMethodMetadata = new<Method>
}
method dynamic DynamicMethodPost(Base MyBase = null)
{
DynamicMethodMetadataPost = new<Method>
}
# ClassA - Contains virtual method to be overridden in ClassB at run-time.
class ClassA
{
method virtual PrintName()
{
StdIO.Write('ClassA')
}
}
# ClassB derived from ClassA - Defined as empty at initial compile session. Must be marked as dynamic.
public class dynamic ClassB from<ClassA>
{
}