c# - How to use "using static" directive for dynamically generated code? -


i want let users input mathematics expression in terms of x , y natural possible. example, instead of typing complex.sin(x), prefer use sin(x).

the following code fails when sin(x), example, defined user.

using microsoft.codeanalysis.csharp.scripting; using system; using system.numerics; using static system.console; using static system.numerics.complex;   namespace mathevaluator {     public class globals     {         public complex x;         public complex y;     }      class program     {          async static void jobasync(microsoft.codeanalysis.scripting.script<complex> script)         {             complex x = new complex(1, 0);             complex y = new complex(0, 1);             try             {                 var result = await script.runasync(new globals { x = x, y = y });                 writeline($"{x} * {y} = {result.returnvalue}\n");             }             catch (exception e)             {                 writeline(e.message);             }         }          static void main(string[] args)         {              console.write("define expression in x , y: ");             string expression = console.readline(); //user input              var script = csharpscript.create<complex>(expression, globalstype: typeof(globals));             script.compile();              jobasync(script);          }     } } 

question

how use using static directive dynamically generated code?

you can supply script options create function define references , imports should set script:

var scriptoptions = scriptoptions.default     .withreferences("system.numerics")     .withimports("system.numerics.complex");  var script = csharpscript.create<complex>(expression, options: scriptoptions, globalstype: typeof(globals)); 

that way, can use sin(x) in input:

define expression in x , y: sin(x) (1, 0) * (0, 1) = (0,841470984807897, 0) 

however, when dealing user input, should consider writing own parser. allows on 1 hand define own “aliases” functions (e.g. lower case sin) or more lenient syntax; on other hand, adds more security because right now, nothing prevents me doing this:

define expression in x , y: system.console.writeline("i hacked calculator!") hacked calculator! (1, 0) * (0, 1) = (0, 0) 

i created quick (and dirty) parser using roslyn’s syntax tree parsing. rather limited (e.g. since requires return values of subexpressions complex), give idea of how work:

void main() {     string input = "y + 3 * sin(x)";     var options = csharpparseoptions.default.withkind(microsoft.codeanalysis.sourcecodekind.script);     var expression = csharpsyntaxtree.parsetext(input, options).getroot().descendantnodes().oftype<expressionstatementsyntax>().firstordefault()?.expression;      console.writeline(evaluateexpression(expression)); }  complex evaluateexpression(expressionsyntax expr) {     if (expr binaryexpressionsyntax)     {         var binexpr = (binaryexpressionsyntax)expr;         var left = evaluateexpression(binexpr.left);         var right = evaluateexpression(binexpr.right);          switch (binexpr.operatortoken.valuetext)         {             case "+":                 return left + right;             case "-":                 return left - right;             case "*":                 return left * right;             case "/":                 return left / right;             default:                 throw new notsupportedexception(binexpr.operatortoken.valuetext);         }     }     else if (expr identifiernamesyntax)     {         return getvalue(((identifiernamesyntax)expr).identifier.valuetext);     }     else if (expr literalexpressionsyntax)     {         var value = ((literalexpressionsyntax)expr).token.value;         return float.parse(value.tostring());     }     else if (expr invocationexpressionsyntax)     {         var invocexpr = (invocationexpressionsyntax)expr;         var args = invocexpr.argumentlist.arguments.select(arg => evaluateexpression(arg.expression)).toarray();         return call(((identifiernamesyntax)invocexpr.expression).identifier.valuetext, args);     }     else         throw new notsupportedexception(expr.gettype().name); }  complex call(string identifier, complex[] args) {     switch (identifier.tolower())     {         case "sin":             return complex.sin(args[0]);         default:             throw new notimplementedexception(identifier);     } }  complex getvalue(string identifier) {     switch (identifier)     {         case "x":             return new complex(1, 0);         case "y":             return new complex(0, 1);         default:             throw new argumentexception("identifier not found", nameof(identifier));     } } 

Comments

Popular posts from this blog

sql - invalid in the select list because it is not contained in either an aggregate function -

Angularjs unit testing - ng-disabled not working when adding text to textarea -

How to start daemon on android by adb -