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}} ]