############################################################################### # # csharp.eagle -- # # Extensible Adaptable Generalized Logic Engine (Eagle) # Eagle CSharp Package File # # Copyright (c) 2007-2012 by Joe Mistachkin. All rights reserved. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: $ # ############################################################################### # # NOTE: Use our own namespace here because even though we do not directly # support namespaces ourselves, we do not want to pollute the global # namespace if this script actually ends up being evaluated in Tcl. # namespace eval ::Eagle { # # NOTE: This procedure is used to dynamically compile some C# code from # within a script. While this procedure was originally designed # to be used by the test suite, it can be quite useful in non-test # scripts as well. # proc compileCSharp { string memory symbols strict resultsVarName errorsVarName args } { # # NOTE: The [object] command is required by this procedure. If it # is not available, bail out now. # if {[llength [info commands object]] == 0} then { # # NOTE: We cannot even attempt to compile anything, fail. # set code Error # # NOTE: Prepare to transfer error messages to the caller. # if {[string length $errorsVarName] > 0} then { upvar 1 $errorsVarName local_errors } # # NOTE: Append to the list of errors. # lappend local_errors "cannot compile, missing \"object\" command" # # NOTE: Return the overall result to the caller. # return $code } # # NOTE: Create the C# code provider object (i.e. the compiler). # set provider [object create -alias Microsoft.CSharp.CSharpCodeProvider] # # NOTE: Create the object that provides various parameters to the C# # code provider (i.e. the compiler options). # set parameters [object create -alias \ System.CodeDom.Compiler.CompilerParameters] # # NOTE: Do we not want to persist the generated assembly to disk? # if {$memory} then { $parameters GenerateInMemory true } # # NOTE: Do we want symbols to be generated for the generated assembly? # if {$symbols} then { $parameters IncludeDebugInformation true } # # NOTE: Make sure that the "standard" preprocessor defines match those # for the platform (i.e. the ones used to compile the Eagle core # library assembly). # set platformOptions [expr { \ [info exists ::eagle_platform(compileOptions)] ? \ $::eagle_platform(compileOptions) : [list]}] # # NOTE: Permit extra C# compiler options to be passed via the global # array element "csharpOptions", if it exists. # set csharpOptions [expr { \ [info exists ::eagle_platform(csharpOptions)] ? \ $::eagle_platform(csharpOptions) : [list]}] if {[llength $platformOptions] > 0 || \ [llength $csharpOptions] > 0} then { # # NOTE: Grab the existing compiler options, if any. # set compilerOptions [$parameters CompilerOptions] if {"DEBUG" in $platformOptions} then { if {[string length $compilerOptions] > 0} then { append compilerOptions " " } append compilerOptions /define:DEBUG } if {"TRACE" in $platformOptions} then { if {[string length $compilerOptions] > 0} then { append compilerOptions " " } append compilerOptions /define:TRACE } # # NOTE: Append the configured extra C# compiler options configured # via the global array element "csharpOptions", if any. # foreach csharpOption $csharpOptions { if {[string length $compilerOptions] > 0} then { append compilerOptions " " } append compilerOptions $csharpOption } # # NOTE: Reset the compiler options to the pre-existing ones plus the # extra defines we may have added (above). # $parameters CompilerOptions $compilerOptions } # # NOTE: Process any extra compiler settings the caller may have # provided. # foreach {name value} $args { $parameters -nocase $name $value } # # NOTE: Prepare to transfer the object reference to the caller. We # must use upvar here because otherwise the object is lost when # the procedure call frame is cleaned up. # if {[string length $resultsVarName] > 0} then { upvar 1 $resultsVarName results } # # NOTE: Attempt to compile the specified string as C# and capture the # results into the variable provided by the caller. # set results [$provider -alias CompileAssemblyFromSource $parameters \ $string] # # NOTE: We no longer need the C# code provider object (i.e. the # compiler); therefore, dispose it now. # unset provider; # dispose # # NOTE: Fetch the collection of compiler errors (which may be empty). # set errors [$results -alias Errors] # # NOTE: It is assumed that no assembly was generated if there were # any compiler errors. Ignore all compiler warnings unless # we are in strict mode. # if {[$errors HasErrors] || ($strict && [$errors HasWarnings])} then { # # NOTE: Compilation of the assembly failed. # set code Error # # NOTE: Prepare to transfer error messages to the caller. # if {[string length $errorsVarName] > 0} then { upvar 1 $errorsVarName local_errors } # # NOTE: How many compile errors? # set count [$errors Count] # # NOTE: Grab each error object and append the string itself to # the overall list of errors. # for {set index 0} {$index < $count} {incr index} { # # NOTE: Get the compiler error object at this index. # set error [$errors -alias Item $index] # # NOTE: Convert it to a string and append it to the list of # errors. # lappend local_errors [$error ToString] # # NOTE: Since the error itself is actually an object, we must # dispose it. # unset error; # dispose } } else { # # NOTE: Compilation of the assembly succeeded. # set code Ok } # # NOTE: We no longer need the collection of compiler errors; # therefore, dispose it now. # unset errors; # dispose # # NOTE: Return the overall result to the caller. # return $code } # # NOTE: Provide the Eagle "C#" package to the interpreter. # package provide Eagle.CSharp \ [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}] }