Mathematica + NETLink + CodeDom- Example 2
- To: mathgroup at smc.vnet.net
- Subject: [mg45304] Mathematica + NETLink + CodeDom- Example 2
- From: ToolmakerSteve at shawstudio.com (ToolmakerSteve)
- Date: Mon, 29 Dec 2003 00:22:11 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
(Follow on to [mg45085] NETLink - CREATING a new class?
I have submitted this to support@wolfram,
and explained that I hope it will be given to a programmer
who is working on NETLink -
so that the problems I encountered in mg45085 can be resolved,
and so that some example like this can be included in the NETLink documentation,
in hopes that some other O-O .NET programmers can be enticed to use Mathematica.
)
Here is a more interesting notebook,
which creates a .NET assembly without
having to type all those "NETNew" expressions.
It contains a package "NetCodeGen",
which is a translator from a simple structure in Mathematica,
which represents the assembly as code snippets within some structural
constructs.
(By The Way, this is far more readable than the XML version of code that some
people are starting to work with in other environments.)
For example, here is "Hello Net World" source code, in its Mathematica form:
Namespace[ "MyNamespace",
Using[
"System",
"System.Windows.Forms"
],
Class[ "HelloWorldMsgApp",
{
EntryMethod[ "Main",
{
"MessageBox.Show( \"Hello, .NET World!\" )"
}
]
}
]
]
Below is the notebook expression with all the details.
-- ToolmakerSteve
= = = = = = = = = = = = = = = = = = = = = = = = = = =
Notebook[{
Cell[TextData[StyleBox["(* 60-HelloNetWorld-SnippetSyntax.\nBetter \
than typing in NETLink expressions to call CodeDom methods, and far \
easier to implement than a full C# recursive descent parser:\nHere is \
a structure translator that builds up a NET assembly from \
code-snippets and CodeDom structural methods,\nby associating a \
symbol with each method.\n*)",
FontSize->14,
FontWeight->"Bold"]], "Subsubtitle"],
Cell[CellGroupData[{
Cell[BoxData[{
\(\(\(BeginPackage["\<NETCodeGen`\>"]\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(Needs["\<NETLink`\>"]\)\(\n\)\(\[IndentingNewLine]\)\( (*\ \
\(--\(-\ Quiet\)\)\ spell\ warnings\ + \
limit\ output\ \(length\ --\) - \ \
*) \)\(\[IndentingNewLine]\)
\) (*\ TBD : \ Hold\ current\ values, \
so\ can\ restore\ at\ end\ of\ \(\(package\)\(.\)\)\ *) \), "\
\[IndentingNewLine]",
\(Off[General::spell]; \ \ \ Off[General::spell1];\), "\n",
\(\($PrePrint =
Short[#, 50] &;\)\[IndentingNewLine]\[IndentingNewLine] (*\
Load\ type \((s)\)\ to\ call\ static\ members . \
Move\ HERE\ for\ \(\(PERFORMANCE\)\(?\)\); \
\[IndentingNewLine]Need\ here\ to\ resolve\ during\ \(\(compilation\)\
\(?\)\)\ *) \), "\[IndentingNewLine]",
\(\(\(LoadNETType[\ "\<System.CodeDom.MemberAttributes\>"\ ];\)\(\
\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(BuildAssembly::usage = \[IndentingNewLine]"\<BuildAssembly[ \
tree1, fileName1 ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(DumpNamespace::usage = \[IndentingNewLine]"\<DumpNamespace[ \
namespace1 ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(Namespace::usage = \[IndentingNewLine]"\<type: Namespace[ \
<name>,Class[...] ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(Using::usage = \[IndentingNewLine]"\<type: Using[ <name>,.. \
]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(Class::usage = \[IndentingNewLine]"\<type: Class[ \
<name>,Using[...], { <member>,.. } ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(EntryMethod::usage = \[IndentingNewLine]"\<type: \
EntryMethod[ <name>, { <statement>,.. } ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(\(Method::usage = \[IndentingNewLine]"\<type: Method[ <name>, \
{ <statement>,.. } ]\>"\)\(\[IndentingNewLine]\)
\)\), "\[IndentingNewLine]",
\(\(Begin["\<`Private`\>"];\)\[IndentingNewLine]\
\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \), "\
\[IndentingNewLine]",
\(\(BuildAssembly[\[IndentingNewLine]Namespace[\[IndentingNewLine]\
namespaceName1_String, \[IndentingNewLine]imports_Using, \
\[IndentingNewLine]type1_Class\ (*\
FUTURE : \
or\ other\ TYPE\ *) \[IndentingNewLine]], \
\[IndentingNewLine]fileName1_\ ] := \[IndentingNewLine]NETBlock[\
\[IndentingNewLine]Module[\ {netSpace1,
netType1}, \[IndentingNewLine]netSpace1 =
NewNamespace[\
namespaceName1\ ]; \[IndentingNewLine]AddImports[\
imports, netSpace1\ ]; \[IndentingNewLine]netType1 =
NewPublicType[\ type1,
netSpace1\ ]; \[IndentingNewLine]\[IndentingNewLine] \
(*\ TBD : \
Compile\ the\ \(\(assembly\)\(.\)\)\ \
*) \[IndentingNewLine]\[IndentingNewLine] (*\
TBD : \
output\ compiled\ assembly\ to\ \(\(file\)\(.\)\)\ \
*) \[IndentingNewLine]"\<assembly \>" <> namespaceName1 <> "\<-->\>" <>
fileName1 //
Print; \[IndentingNewLine]\[IndentingNewLine] (*\
TESTING - \
dump\ contents\ of\ \(\(assembly\)\(.\)\)\ \
*) \[IndentingNewLine]DumpNamespace[\
netSpace1\ ]; \[IndentingNewLine] (*\
NOTE : \
If\ this\ RETURNS\ netSpace1, \[IndentingNewLine]then\
\ "\<netSpace1\>"\ escapes\ "\<NETBlock[..]\>"\ - \
\[IndentingNewLine]in\ which\ case\ client\ should\ call\ \
"\<ReleaseNETObject[ netSpace1 ]\>"\ *) \[IndentingNewLine] (*\
netSpace1\ *) \[IndentingNewLine]]\[IndentingNewLine]];\
\)\[IndentingNewLine]\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\
\)\)\)\)\)\ *) \), "\[IndentingNewLine]",
\(\(DumpNamespace[\
netSpace1_\ ] := \[IndentingNewLine]Module[\ {}, \
\[IndentingNewLine]"\<Namespace: \>" <> \((netSpace1@Name)\) //
Print; \[IndentingNewLine]DumpImports[\
netSpace1\ ]; \[IndentingNewLine]DumpTypes[\
netSpace1\ ];\[IndentingNewLine]];\)\[IndentingNewLine]\
\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \), "\
\[IndentingNewLine]",
\(\(NewNamespace[\
namespaceName1_String\ ] := \[IndentingNewLine]Module[\ \
{netSpace1}, \[IndentingNewLine]netSpace1 =
NETNew[\ "\<System.CodeDom.CodeNamespace\>"\ ]; \
\[IndentingNewLine]netSpace1@Name =
namespaceName1; \[IndentingNewLine]netSpace1\
\[IndentingNewLine]];\)\[IndentingNewLine]\[IndentingNewLine] (*\ \(\
--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \), "\[IndentingNewLine]",
\(\(AddImports[\ imports_,
netSpace1_\ ] := \[IndentingNewLine]Module[\ {netImports}, \
\[IndentingNewLine]netImports =
netSpace1@Imports; \[IndentingNewLine]Map[\
AddImport[\ #, netImports\ ] &,
imports\ ];\[IndentingNewLine]];\)\[IndentingNewLine]\), \
"\[IndentingNewLine]",
\(\(AddImport[\ importName1_String,
netImports_\ ] := \[IndentingNewLine]netImports@
Add[\ NETNew[\ "\<System.CodeDom.CodeNamespaceImport\>",
importName1\ ]\ ];\)\[IndentingNewLine]\), "\
\[IndentingNewLine]",
\(\(DumpImports[\
netSpace1_\ ] := \[IndentingNewLine]Module[\ {netImports,
count}, \[IndentingNewLine]netImports =
netSpace1@Imports; \[IndentingNewLine]count =
netImports@
Count; \[IndentingNewLine] (*\ \("\<# imports: \>" <>
ToString[\ count\ ] //
Print;\)\ \
*) \[IndentingNewLine]Do[\[IndentingNewLine]DumpImport[\
netImports@Item[\ i - 1\ ]\ ], \ (*\
ZERO - BASED\ *) \[IndentingNewLine]{i,
count}\[IndentingNewLine]];\[IndentingNewLine]];\)\
\[IndentingNewLine]\), "\[IndentingNewLine]",
\(\(DumpImport[\
import1_\ ] := \[IndentingNewLine]Module[\ {}, \
\[IndentingNewLine]\("\<using: \>" <> \((import1@Namespace)\) //
Print;\)\[IndentingNewLine]];\)\[IndentingNewLine]\
\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \), "\
\[IndentingNewLine]",
\(\(NewPublicType[\
Class[\[IndentingNewLine]className1_String, \
\[IndentingNewLine]members_List\[IndentingNewLine]],
netSpace1_\ ] := \[IndentingNewLine]Module[\ {class1}, \
\[IndentingNewLine]class1 =
NewPublicType[\ className1, netSpace1,
True\ ]; \[IndentingNewLine]AddMembers[\ members,
class1\ ]; \[IndentingNewLine]class1\[IndentingNewLine]];\
\)\[IndentingNewLine]\), "\[IndentingNewLine]",
\(\(NewPublicType[\ typeName1_String, netSpace1_,
isClass_Symbol\ ] := \[IndentingNewLine]Module[\ {netType1,
spaceTypes1}, \[IndentingNewLine] (*\
Load\ type \((s)\)\ to\ call\ static\ members . \ \
\(\(PERFORMANCE\)\(?\)\)\ *) \[IndentingNewLine]LoadNETType[\ \
"\<System.CodeDom.MemberAttributes\>"\ ]; \[IndentingNewLine]\
\[IndentingNewLine]netType1 =
NETNew[\ "\<System.CodeDom.CodeTypeDeclaration\>"\ ]; \
\[IndentingNewLine]netType1@Name =
typeName1; \[IndentingNewLine]netType1@IsClass =
isClass; \[IndentingNewLine] (*\ \(TBD\ netType1@
Attributes =
MemberAttributes`Public;\)\ *) \[IndentingNewLine]\
\[IndentingNewLine]spaceTypes1 =
netSpace1@Types; \[IndentingNewLine]spaceTypes1@
Add[\ netType1\ ]; \[IndentingNewLine]netType1\
\[IndentingNewLine]];\)\[IndentingNewLine]\), "\[IndentingNewLine]",
\(\(DumpTypes[\
netSpace1_\ ] := \[IndentingNewLine]Module[\ {netTypes,
count}, \[IndentingNewLine]netTypes =
netSpace1@Types; \[IndentingNewLine]count =
netTypes@Count; \[IndentingNewLine]"\<# types: \>" <>
ToString[\ count\ ] //
Print; \[IndentingNewLine]Do[\[IndentingNewLine]DumpType[\
\ netTypes@Item[\ i - 1\ ]\ ], \ (*\
ZERO - BASED\ *) \[IndentingNewLine]{i,
count}\ ];\[IndentingNewLine]];\)\[IndentingNewLine]\), \
"\[IndentingNewLine]",
\(\(DumpType[\
netType1_\ ] := \[IndentingNewLine]Module[\ {}, \
\[IndentingNewLine]"\<type: \>" <> \((netType1@Name)\) //
Print; \[IndentingNewLine]DumpMembers[\
netType1\ ];\[IndentingNewLine]];\)\[IndentingNewLine]\
\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \), "\
\[IndentingNewLine]",
\(\(AddMembers[\ members_List,
type1_\ ] := \[IndentingNewLine]Module[\ {}, \
\[IndentingNewLine]\(Map[\ AddMember[\ #, type1\ ] &,
members\ ];\)\[IndentingNewLine]];\)\[IndentingNewLine]\
\), "\[IndentingNewLine]",
\(\(AddMember[\ memberStuff_,
type1_\ ] := \[IndentingNewLine]Module[\ {member1}, \
\[IndentingNewLine]member1 =
BuildMember[\
memberStuff\ ]; \[IndentingNewLine]\((type1@Members)\)@
Add[\ member1\ ]; \[IndentingNewLine]member1\
\[IndentingNewLine]];\)\[IndentingNewLine]\[IndentingNewLine] (*\
TBD : \ Does\ this\ care\ what\ type\ it\ is\ building\ member\ \
\(\(for\)\(?\)\)\ *) \), "\[IndentingNewLine]",
\(\(BuildMember[\[IndentingNewLine]EntryMethod[\
methodName_String,
statements_List\ ]\ ] := \[IndentingNewLine]Module[\ \
{method1}, \[IndentingNewLine]method1 =
NETNew[\ "\<System.CodeDom.CodeEntryPointMethod\>"\ ]; \
\[IndentingNewLine]method1@Name =
methodName; \[IndentingNewLine]\[IndentingNewLine] (*\
Load\ type \((s)\)\ to\ call\ static\ members . \ \
\(\(PERFORMANCE\)\(?\)\)\ *) \[IndentingNewLine]LoadNETType[\ \
"\<System.CodeDom.MemberAttributes\>"\ ]; \[IndentingNewLine] (*\ \
\(TBD\ method1@Attributes =
NetMergeAttributes[\ MemberAttributes`Public,
MemberAttributes`Static\ ];\)\ \
*) \[IndentingNewLine]\[IndentingNewLine]Map[\
AddStatement[\ #, method1\ ] &,
statements\ ]; \[IndentingNewLine]method1\
\[IndentingNewLine]];\)\[IndentingNewLine]\), "\[IndentingNewLine]",
\(\(DumpMembers[\
netType1_\ ] := \[IndentingNewLine]Module[\ {netMembers,
count}, \[IndentingNewLine]netMembers =
netType1@Members; \[IndentingNewLine]count =
netMembers@Count; \[IndentingNewLine]"\<# members: \>" <>
ToString[\ count\ ] //
Print; \[IndentingNewLine]Do[\[IndentingNewLine]\
DumpMember[\ netMembers@Item[\ i - 1\ ]\ ], \ (*\
ZERO - BASED\ *) \[IndentingNewLine]{i,
count}\ ];\[IndentingNewLine]];\)\[IndentingNewLine]\), \
"\[IndentingNewLine]",
\(\(DumpMember[\
netMember1_\ ] := \[IndentingNewLine]Module[\ {}, \
\[IndentingNewLine]"\<member: \>" <> \((netMember1@Name)\) //
Print; \[IndentingNewLine] (*\
TBD : \ Depends\ on\ TYPE\ of\ member\ [field, property,
method]\ *) \[IndentingNewLine] (*\ \
\(DumpStatements[\
netMember1\ ];\)\ *) \[IndentingNewLine]];\)\
\[IndentingNewLine]\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\
\)\)\)\)\ *) \[IndentingNewLine] (*\
Simplest\ statement\ is\ a\ code\ snippet\ in\ C \( \
\(#\)\(.\)\)\ *) \), "\[IndentingNewLine]",
\(\(AddStatement[\ snippetString_String,
method1_\ ] := \[IndentingNewLine]Module[\ {statement1,
snippet1}, \[IndentingNewLine]snippet1 =
NewSnippet[\
snippetString\ ]; \[IndentingNewLine]statement1 =
NETNew[\ "\<System.CodeDom.CodeExpressionStatement\>",
snippet1\ ]; \[IndentingNewLine]\((method1@
Statements)\)@
Add[\ statement1\ ];\[IndentingNewLine]];\)\
\[IndentingNewLine]\[IndentingNewLine] (*\
TBD : \ Statements\ representing\ logic\ structures; \
\[IndentingNewLine]e .
g . \ "\<If\>", \ \(\("\<Do\>"\)\(.\)\)\ *) \
\[IndentingNewLine]\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\
\)\)\)\)\ *) \), "\[IndentingNewLine]",
\(\(NewSnippet[\
snippetString_String\ ] := \[IndentingNewLine]NETNew[\ \
"\<System.CodeDom.CodeSnippetExpression\>", \
\[IndentingNewLine]snippetString\ ];\)\[IndentingNewLine]\
\[IndentingNewLine] (*\ \(--\(--\(-\ \ \(--\(---\)\)\)\)\)\ *) \
\[IndentingNewLine] (*\ "\<net1 | net2\>"\ *) \), \
"\[IndentingNewLine]",
\(\(NetBitOr[\ net1_, net2_\ ] := \[IndentingNewLine]BitOr[\
NETObjectToExpression[\ net1\ ],
NETObjectToExpression[\
net2\ ]\ ];\)\[IndentingNewLine]\[IndentingNewLine] (*\
TBD : \ haven'
t\ found\ a\ way\ to\ do\ this\ yet . \
TBD\ *) \), "\[IndentingNewLine]",
\(\(NetMergeAttributes[\ net1_, net2_\ ] :=
net1\ (*\ \(|\)\(\ \)\(net2\)\ *) ;\)\[IndentingNewLine]\), \
"\[IndentingNewLine]",
\(\(End[];\)\), "\[IndentingNewLine]",
\(EndPackage[]\)}], "Input"],
Cell[BoxData[
\("NETCodeGen`"\)], "Output"],
Cell[BoxData[
TagBox["\<\"BuildAssembly[ tree1, fileName1 ]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"DumpNamespace[ namespace1 ]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"type: Namespace[ <name>,Class[...] ]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"type: Using[ <name>,.. ]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"type: Class[ <name>,Using[...], { <member>,.. } \
]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"type: EntryMethod[ <name>, { <statement>,.. } ]\"\>",
(Short[ #, 50]&)]], "Output"],
Cell[BoxData[
TagBox["\<\"type: Method[ <name>, { <statement>,.. } ]\"\>",
(Short[ #, 50]&)]], "Output"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
\(\(\( (*\
An\ example\ assembly\ \
*) \)\(\[IndentingNewLine]\)\(helloNetWorld\[Bullet]Tree = \
\[IndentingNewLine]Namespace[\ "\<MyNamespace\>", \
\[IndentingNewLine]Using[\[IndentingNewLine]"\<System\>", \
\[IndentingNewLine]"\<System.Windows.Forms\>"\[IndentingNewLine]], \
\[IndentingNewLine]Class[\ "\<HelloWorldMsgApp\>", \
\[IndentingNewLine]{\[IndentingNewLine]EntryMethod[\ "\<Main\>", \
\[IndentingNewLine]{\[IndentingNewLine]\ "\<MessageBox.Show( \"Hello, \
.NET World!\" )\>"\[IndentingNewLine]}\[IndentingNewLine]]\
\[IndentingNewLine]}\[IndentingNewLine]]\[IndentingNewLine]]\)\)\)], \
"Input"],
Cell[BoxData[
TagBox[\(Namespace["MyNamespace",
Using["System", "System.Windows.Forms"],
Class["HelloWorldMsgApp", {EntryMethod[
"Main", {"MessageBox.Show( \"Hello, .NET World!\" \
)"}]}]]\),
(Short[ #, 50]&)]], "Output"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
\(BuildAssembly[\
helloNetWorld\[Bullet]Tree, "\<c:\\Temp\\HelloWorldMsg.exe\>"\ \
]\)], "Input"],
Cell[BoxData[
\("assembly MyNamespace-->c:\\Temp\\HelloWorldMsg.exe"\)], \
"Print"],
Cell[BoxData[
\("Namespace: MyNamespace"\)], "Print"],
Cell[BoxData[
\("using: System"\)], "Print"],
Cell[BoxData[
\("using: System.Windows.Forms"\)], "Print"],
Cell[BoxData[
\("# types: 1"\)], "Print"],
Cell[BoxData[
\("type: HelloWorldMsgApp"\)], "Print"],
Cell[BoxData[
\("# members: 1"\)], "Print"],
Cell[BoxData[
\("member: Main"\)], "Print"]
}, Open ]]
},
FrontEndVersion->"5.0 for Microsoft Windows",
ScreenRectangle->{{0, 1280}, {0, 971}},
CellGrouping->Manual,
WindowSize->{645, 843},
WindowMargins->{{5, Automatic}, {10, Automatic}}
]