CSharpILParser.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. #if REFLECTION_EMIT_COMPILER
  2. using Microsoft.CodeAnalysis.CSharp.Syntax;
  3. using Microsoft.CodeAnalysis.CSharp;
  4. using System.Reflection.Emit;
  5. using System.Reflection;
  6. using System.Diagnostics;
  7. using System.Linq.Expressions;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Security.Cryptography;
  11. using FastReport.Utils;
  12. using System.Linq;
  13. using System.Runtime.CompilerServices;
  14. #if DEBUG
  15. using ILGenerator = FastReport.Code.Expressions.ILGeneratorDebugger;
  16. #endif
  17. namespace FastReport.Code.Expressions
  18. {
  19. /* TODO:
  20. * new [] {}
  21. * static Type searching
  22. * extension methods
  23. * 'dynamic' support
  24. */
  25. internal sealed class CSharpILParser : ILParser
  26. {
  27. ILGenerator gen;
  28. private readonly Report _report;
  29. private Type[] argTypes;
  30. private static readonly Type _returnType = typeof(object);
  31. public CSharpILParser(Report report)
  32. {
  33. _report = report;
  34. }
  35. protected override MethodInfo CompileExpression(string expression, Type[] argTypes)
  36. {
  37. ExpressionSyntax parse = SyntaxFactory.ParseExpression(expression);
  38. return StartDynamic(parse, argTypes);
  39. }
  40. private MethodInfo StartDynamic(ExpressionSyntax expressionSyntax, Type[] argTypes)
  41. {
  42. const string myMthdName = "CalcExpression";
  43. this.argTypes = argTypes;
  44. DynamicMethod dynamicMethod = new DynamicMethod(myMthdName,
  45. _returnType,
  46. argTypes,
  47. typeof(ILGenerator).Module,
  48. true
  49. //typeof(string).Module
  50. );
  51. #if DEBUG
  52. gen = new ILGeneratorDebugger(dynamicMethod.GetILGenerator());
  53. #else
  54. gen = dynamicMethod.GetILGenerator();
  55. #endif
  56. StartParse(expressionSyntax);
  57. return dynamicMethod;
  58. }
  59. private void StartParse(ExpressionSyntax expressionSyntax)
  60. {
  61. Type returnType = ParseToIL(expressionSyntax);
  62. CastTo(returnType, _returnType);
  63. gen.Emit(OpCodes.Ret);
  64. }
  65. public Type ParseToIL(ExpressionSyntax expression, Type leftType = null)
  66. {
  67. if (expression is BinaryExpressionSyntax binary)
  68. return BinaryOp(binary);
  69. else if (expression is LiteralExpressionSyntax literal)
  70. return PutValueOnStack(literal.Token.Value);
  71. else if (expression is InvocationExpressionSyntax invocation)
  72. return ParseToIL(invocation.Expression, leftType);
  73. else if (expression is MemberAccessExpressionSyntax memberAccess)
  74. return MemberAccessOp(memberAccess);
  75. else if (expression is IdentifierNameSyntax identifierName)
  76. return SearchIdentifier(identifierName, leftType);
  77. else if (expression is PredefinedTypeSyntax predefinedType)
  78. return ParsePredefinedType(predefinedType.Keyword.Value.ToString());
  79. else if (expression is PostfixUnaryExpressionSyntax postfixUnary)
  80. return UnaryPostOp(postfixUnary);
  81. else if (expression is PrefixUnaryExpressionSyntax prefixUnary)
  82. return UnaryPreOp(prefixUnary);
  83. else if (expression is ConditionalExpressionSyntax conditional) // a ? b : c
  84. return ConditionalOp(conditional);
  85. else if (expression is AssignmentExpressionSyntax assignment) // =
  86. return AssignmentOp(assignment);
  87. else if (expression is ParenthesizedExpressionSyntax parenthesized) // (a)
  88. return ParseToIL(parenthesized.Expression, leftType);
  89. else if (expression is CastExpressionSyntax cast) // ()a
  90. return ExplicitCastOp(cast);
  91. else if (expression is ConditionalAccessExpressionSyntax conditionalAccess) // ?.
  92. return ConditionalAccessOp(conditionalAccess);
  93. else if (expression is MemberBindingExpressionSyntax memberBinding)
  94. return MemberAccessOp(memberBinding, leftType);
  95. else if (expression is ElementAccessExpressionSyntax elementAccess) // a[0]
  96. return ElementAccessOp(elementAccess);
  97. else if (expression is ArrayCreationExpressionSyntax arrayCreation) // new int[] { }
  98. {
  99. // TODO:
  100. var arrayType = ParseToIL(arrayCreation.Type);
  101. }
  102. else if (expression is ImplicitArrayCreationExpressionSyntax implicitArrayCreation) // new[] { }
  103. {
  104. }
  105. throw new NotImplementedException();
  106. }
  107. private Type SearchIdentifier(IdentifierNameSyntax identifierName, Type leftType)
  108. {
  109. var identifier = identifierName.Identifier.ValueText;
  110. // leftType can be null => it's static class etc
  111. if (identifierName.Parent is InvocationExpressionSyntax invocation)
  112. {
  113. // method:
  114. Type[] argumentTypes = ExecuteArguments(invocation.ArgumentList);
  115. FunctionInfo info = RegisteredObjects.Functions.Find(identifier);
  116. if (info == null)
  117. throw new NotSupportedException($"Method '{identifier}' wasn't found");
  118. return MethodCall(leftType, info.Function);
  119. }
  120. else
  121. {
  122. // class, parameter, property, field etc
  123. if (identifier == "Report") // hard
  124. {
  125. return LoadReport();
  126. }
  127. else if (identifier == "Value")
  128. {
  129. gen.Emit(OpCodes.Ldarg_1);
  130. return argTypes[1];
  131. }
  132. else if (identifier == "Engine")
  133. {
  134. var reportType = LoadReport();
  135. return MemberAccessOp(identifier, identifierName, reportType);
  136. }
  137. var type = ParseKnownType(identifier);
  138. if (type != null)
  139. return type;
  140. // report objects
  141. Base obj = _report.FindObject(identifier);
  142. if (obj != null)
  143. {
  144. // IT'S DYNAMIC STATE! We should't store it!
  145. var reportType = LoadReport();
  146. var argType = PutValueOnStack(identifier);
  147. var findObjectMethod = reportType.GetMethod(nameof(_report.FindObject), new[] {argType});
  148. var findObjectReturnType = MethodCall(reportType, findObjectMethod);
  149. // cast to necessary type:
  150. var reportObjectType = obj.GetType();
  151. CastTo(findObjectReturnType, reportObjectType);
  152. return reportObjectType;
  153. }
  154. if (type == null)
  155. type = Type.GetType(identifier, false, false);
  156. if (type != null)
  157. return type;
  158. }
  159. throw new NotSupportedException();
  160. }
  161. private Type LoadReport()
  162. {
  163. gen.Emit(OpCodes.Ldarg_0);
  164. return argTypes[0];
  165. }
  166. private static Type ParsePredefinedType(string typeName)
  167. {
  168. switch (typeName)
  169. {
  170. case "object": return typeof(object);
  171. case "string": return typeof(string);
  172. case "bool": return typeof(bool);
  173. case "byte": return typeof(byte);
  174. case "sbyte": return typeof(sbyte);
  175. case "char": return typeof(char);
  176. case "short": return typeof(short);
  177. case "ushort": return typeof(ushort);
  178. case "int": return typeof(int);
  179. case "uint": return typeof(uint);
  180. case "long": return typeof(long);
  181. case "ulong": return typeof(ulong);
  182. case "float": return typeof(float);
  183. case "double": return typeof(double);
  184. case "decimal": return typeof(decimal);
  185. }
  186. throw new NotSupportedException();
  187. }
  188. private static Type ParseKnownType(string typeName)
  189. {
  190. switch (typeName)
  191. {
  192. case "Object": return typeof(object);
  193. case "String": return typeof(string);
  194. case "Boolean": return typeof(Boolean);
  195. case "Byte": return typeof(Byte);
  196. case "SByte": return typeof(SByte);
  197. case "Char": return typeof(Char);
  198. case "Int16": return typeof(Int16);
  199. case "UInt16": return typeof(UInt16);
  200. case "Int32": return typeof(Int32);
  201. case "UInt32": return typeof(UInt32);
  202. case "Int64": return typeof(Int64);
  203. case "UInt64": return typeof(UInt64);
  204. case "Single": return typeof(Single);
  205. case "Double": return typeof(Double);
  206. case "Decimal": return typeof(Decimal);
  207. case "DateTime": return typeof(DateTime);
  208. case "DateTimeOffset": return typeof(DateTimeOffset);
  209. }
  210. return null;
  211. }
  212. private Type MemberAccessOp(MemberAccessExpressionSyntax memberAccess)
  213. {
  214. Type type = ParseToIL(memberAccess.Expression);
  215. var name = memberAccess.Name.Identifier.ValueText;
  216. return MemberAccessOp(name, memberAccess, type);
  217. }
  218. private Type MemberAccessOp(MemberBindingExpressionSyntax memberAccess, Type leftType)
  219. {
  220. var name = memberAccess.Name.Identifier.ValueText;
  221. return MemberAccessOp(name, memberAccess, leftType);
  222. }
  223. private Type MemberAccessOp(string name, ExpressionSyntax expression, Type leftType)
  224. {
  225. if (expression.Parent is InvocationExpressionSyntax invocation)
  226. {
  227. // method
  228. Type[] argumentTypes = ExecuteArguments(invocation.ArgumentList);
  229. var methodInfo = CustomMethodSearcher.Search(leftType, name, argumentTypes);
  230. return MethodCall(leftType, methodInfo);
  231. }
  232. else
  233. {
  234. // property or field
  235. var property = leftType.GetProperty(name);
  236. // if it's not a property => try to find a field
  237. if (property == null)
  238. {
  239. var field = leftType.GetField(name);
  240. gen.Emit(OpCodes.Ldfld, field);
  241. return field.FieldType;
  242. }
  243. // only get
  244. var methodInfo = property.GetGetMethod();
  245. return MethodCall(leftType, methodInfo);
  246. }
  247. }
  248. private Type MethodCall(Type targetType, MethodInfo methodInfo)
  249. {
  250. if (methodInfo.IsStatic)
  251. {
  252. gen.EmitCall(OpCodes.Call, methodInfo, null);
  253. }
  254. else
  255. {
  256. if (targetType.IsValueType)
  257. {
  258. // if local:
  259. var local = gen.DeclareLocal(targetType);
  260. gen.Emit(OpCodes.Stloc, local);
  261. gen.Emit(OpCodes.Ldloca_S, local);
  262. gen.EmitCall(OpCodes.Call, methodInfo, null);
  263. }
  264. else
  265. gen.EmitCall(OpCodes.Callvirt, methodInfo, null);
  266. }
  267. return methodInfo.ReturnType;
  268. }
  269. private Type AssignmentOp(AssignmentExpressionSyntax assignment)
  270. {
  271. var type = ParseToIL(assignment.Right);
  272. ParseToIL(assignment.Left);
  273. if (false) // if field
  274. {
  275. var local = gen.DeclareLocal(type);
  276. gen.Emit(OpCodes.Starg_S, local);
  277. }
  278. // TODO: assignment
  279. throw new NotImplementedException();
  280. //return type;
  281. return typeof(void);
  282. }
  283. private Type[] ExecuteArguments(BaseArgumentListSyntax argumentList)
  284. {
  285. var arguments = argumentList.Arguments;
  286. List<Type> types = new List<Type>();
  287. foreach (var argument in arguments)
  288. {
  289. var resultTypeArg = ParseToIL(argument.Expression);
  290. types.Add(resultTypeArg);
  291. }
  292. return types.ToArray();
  293. }
  294. private Type ConditionalOp(ConditionalExpressionSyntax conditional)
  295. {
  296. Label ifTrue = gen.DefineLabel();
  297. Label next = gen.DefineLabel();
  298. var conditionType = ParseToIL(conditional.Condition);
  299. //if (conditionType != typeof(bool))
  300. // throw new Exception();
  301. gen.Emit(OpCodes.Brtrue_S, ifTrue);
  302. var type1 = ParseToIL(conditional.WhenFalse);
  303. gen.Emit(OpCodes.Br_S, next);
  304. gen.MarkLabel(ifTrue);
  305. var type2 = ParseToIL(conditional.WhenTrue);
  306. gen.MarkLabel(next);
  307. //if (type1 != type2)
  308. // throw new Exception();
  309. return type1;
  310. }
  311. private Type ConditionalAccessOp(ConditionalAccessExpressionSyntax conditionalAccess)
  312. {
  313. Label ifTrue = gen.DefineLabel();
  314. Label next = gen.DefineLabel();
  315. var type = ParseToIL(conditionalAccess.Expression);
  316. gen.Emit(OpCodes.Dup);
  317. gen.Emit(OpCodes.Brtrue_S, ifTrue);
  318. gen.Emit(OpCodes.Pop);
  319. gen.Emit(OpCodes.Ldnull);
  320. gen.Emit(OpCodes.Br_S, next);
  321. gen.MarkLabel(ifTrue);
  322. var resultType = ParseToIL(conditionalAccess.WhenNotNull, type);
  323. gen.MarkLabel(next);
  324. return resultType;
  325. }
  326. private Type UnaryPreOp(PrefixUnaryExpressionSyntax prefixUnary)
  327. {
  328. var kind = prefixUnary.Kind();
  329. var op = prefixUnary.Operand;
  330. Type returnType = ParseToIL(op);
  331. if (returnType == typeof(decimal))
  332. return BinaryCustomTypeOp(returnType, kind);
  333. switch (kind)
  334. {
  335. case SyntaxKind.BitwiseNotExpression: // ~
  336. gen.Emit(OpCodes.Not);
  337. break;
  338. case SyntaxKind.UnaryMinusExpression: // -
  339. gen.Emit(OpCodes.Neg);
  340. break;
  341. case SyntaxKind.LogicalNotExpression: // !
  342. returnType = CompareWithZero();
  343. break;
  344. case SyntaxKind.PreIncrementExpression: // ++a
  345. gen.Emit(OpCodes.Ldc_I4_1);
  346. gen.Emit(OpCodes.Add);
  347. break;
  348. case SyntaxKind.PreDecrementExpression: // --a
  349. gen.Emit(OpCodes.Ldc_I4_1);
  350. gen.Emit(OpCodes.Sub);
  351. break;
  352. }
  353. return returnType;
  354. }
  355. private Type UnaryPostOp(PostfixUnaryExpressionSyntax postfixUnary)
  356. {
  357. var op = postfixUnary.Operand;
  358. var kind = postfixUnary.Kind();
  359. Type returnType = ParseToIL(op);
  360. if (returnType == typeof(decimal))
  361. return BinaryCustomTypeOp(returnType, kind);
  362. switch (kind)
  363. {
  364. case SyntaxKind.PostIncrementExpression: // a++
  365. gen.Emit(OpCodes.Ldc_I4_1);
  366. gen.Emit(OpCodes.Add);
  367. break;
  368. case SyntaxKind.PostDecrementExpression: // a--
  369. gen.Emit(OpCodes.Ldc_I4_1);
  370. gen.Emit(OpCodes.Sub);
  371. break;
  372. }
  373. return returnType;
  374. }
  375. private Type PutValueOnStack(object value)
  376. {
  377. if (value == null)
  378. {
  379. gen.Emit(OpCodes.Ldnull);
  380. return typeof(object);
  381. }
  382. var type = value.GetType();
  383. if (type == typeof(int))
  384. {
  385. gen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
  386. }
  387. else if (type == typeof(bool))
  388. {
  389. if (Convert.ToBoolean(value))
  390. gen.Emit(OpCodes.Ldc_I4_1);
  391. else
  392. gen.Emit(OpCodes.Ldc_I4_0);
  393. }
  394. else if (type == typeof(float))
  395. {
  396. gen.Emit(OpCodes.Ldc_R4, Convert.ToSingle(value));
  397. }
  398. else if (type == typeof(double))
  399. {
  400. gen.Emit(OpCodes.Ldc_R8, Convert.ToDouble(value));
  401. }
  402. //else if (type == typeof(char)) // => int32
  403. //{}
  404. else if (type == typeof(string))
  405. {
  406. gen.Emit(OpCodes.Ldstr, Convert.ToString(value));
  407. }
  408. else if (type == typeof(long))
  409. {
  410. gen.Emit(OpCodes.Ldc_I8, Convert.ToInt64(value));
  411. }
  412. else
  413. {
  414. gen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
  415. }
  416. return type;
  417. }
  418. private Type ElementAccessOp(ElementAccessExpressionSyntax elementAccess)
  419. {
  420. var type = ParseToIL(elementAccess.Expression);
  421. var args = ExecuteArguments(elementAccess.ArgumentList);
  422. if(type.IsArray)
  423. {
  424. var elementType = type.GetElementType();
  425. if (elementType.IsClass || elementType.IsInterface)
  426. gen.Emit(OpCodes.Ldelem_Ref);
  427. else
  428. gen.Emit(OpCodes.Ldelem, elementType);
  429. return elementType;
  430. }
  431. else
  432. {
  433. string propertyName = "Item";
  434. if (type == typeof(string))
  435. propertyName = "Chars";
  436. var property = type.GetProperty(propertyName, args);
  437. var method = property.GetGetMethod();
  438. return MethodCall(type, method);
  439. }
  440. }
  441. private Type BinaryOp(BinaryExpressionSyntax binary)
  442. {
  443. var kind = binary.Kind();
  444. switch(kind)
  445. {
  446. case SyntaxKind.LogicalOrExpression:
  447. case SyntaxKind.LogicalAndExpression:
  448. return LogicalOp(binary, kind);
  449. case SyntaxKind.IsExpression:
  450. case SyntaxKind.AsExpression:
  451. return IsAsOp(binary, kind);
  452. default:
  453. return BinaryOpWithCast(binary, kind);
  454. }
  455. }
  456. private Type BinaryOpWithCast(BinaryExpressionSyntax binary, SyntaxKind kind)
  457. {
  458. Type leftType = ParseToIL(binary.Left);
  459. Type rightType = ParseToIL(binary.Right);
  460. if (leftType == typeof(Variant) || rightType == typeof(Variant))
  461. return VariantOp(kind, leftType, rightType);
  462. Type returnType = CastToGreaterType(leftType, rightType);
  463. if (returnType == typeof(decimal) || returnType == typeof(string))
  464. return BinaryCustomTypeOp(returnType, kind);
  465. switch (kind)
  466. {
  467. case SyntaxKind.AddExpression: // +
  468. gen.Emit(OpCodes.Add);
  469. break;
  470. case SyntaxKind.SubtractExpression: // -
  471. gen.Emit(OpCodes.Sub);
  472. break;
  473. case SyntaxKind.MultiplyExpression: // *
  474. gen.Emit(OpCodes.Mul);
  475. break;
  476. case SyntaxKind.DivideExpression: // /
  477. gen.Emit(OpCodes.Div);
  478. break;
  479. case SyntaxKind.ModuloExpression: // %
  480. gen.Emit(OpCodes.Rem);
  481. break;
  482. case SyntaxKind.EqualsExpression: // ==
  483. gen.Emit(OpCodes.Ceq);
  484. returnType = typeof(bool);
  485. break;
  486. case SyntaxKind.NotEqualsExpression: // !=
  487. // == and NOT
  488. gen.Emit(OpCodes.Ceq);
  489. returnType = CompareWithZero();
  490. break;
  491. case SyntaxKind.LessThanExpression: // <
  492. gen.Emit(OpCodes.Clt);
  493. returnType = typeof(bool);
  494. break;
  495. case SyntaxKind.LessThanOrEqualExpression: // <=
  496. // > and NOT
  497. gen.Emit(OpCodes.Cgt);
  498. returnType = CompareWithZero();
  499. break;
  500. case SyntaxKind.GreaterThanExpression: // >
  501. gen.Emit(OpCodes.Cgt);
  502. returnType = typeof(bool);
  503. break;
  504. case SyntaxKind.GreaterThanOrEqualExpression: // >=
  505. // < and NOT
  506. gen.Emit(OpCodes.Clt);
  507. returnType = CompareWithZero();
  508. break;
  509. case SyntaxKind.BitwiseOrExpression: // |
  510. gen.Emit(OpCodes.Or);
  511. break;
  512. case SyntaxKind.ExclusiveOrExpression: // ^
  513. gen.Emit(OpCodes.Xor);
  514. break;
  515. case SyntaxKind.BitwiseAndExpression: // &
  516. gen.Emit(OpCodes.And);
  517. break;
  518. }
  519. return returnType;
  520. }
  521. private Type BinaryCustomTypeOp(Type type, SyntaxKind kind)
  522. {
  523. string methodName = GetOperatorName(kind);
  524. MethodInfo method;
  525. if (type == typeof(string) && kind == SyntaxKind.AddExpression)
  526. method = type.GetMethod(nameof(string.Concat), new Type[] { type, type });
  527. else
  528. method = type.GetMethod(methodName);
  529. return MethodCall(type, method);
  530. }
  531. private Type VariantOp(SyntaxKind kind, Type left, Type right)
  532. {
  533. Type variantType = typeof(Variant);
  534. string methodName = GetOperatorName(kind);
  535. MethodInfo method = variantType.GetMethod(methodName);
  536. // because 1 argument in Variant must be 'Variant'
  537. if (left != variantType)
  538. PreviousCastTo(left, variantType);
  539. // because 2 argument in Variant operator is object
  540. var parameters = method.GetParameters();
  541. if (parameters.Length == 2)
  542. {
  543. CastTo(right, parameters[1].ParameterType);
  544. }
  545. return MethodCall(variantType, method);
  546. }
  547. private static string GetOperatorName(SyntaxKind kind)
  548. {
  549. string methodName;
  550. switch (kind)
  551. {
  552. case SyntaxKind.AddExpression: // +
  553. methodName = "op_Addition";
  554. break;
  555. case SyntaxKind.SubtractExpression: // -
  556. methodName = "op_Subtraction";
  557. break;
  558. case SyntaxKind.MultiplyExpression: // *
  559. methodName = "op_Multiply";
  560. break;
  561. case SyntaxKind.DivideExpression: // /
  562. methodName = "op_Division";
  563. break;
  564. case SyntaxKind.ModuloExpression: // %
  565. methodName = "op_Modulus";
  566. break;
  567. case SyntaxKind.EqualsExpression: // ==
  568. methodName = "op_Equality";
  569. break;
  570. case SyntaxKind.NotEqualsExpression: // !=
  571. methodName = "op_Inequality";
  572. break;
  573. case SyntaxKind.LessThanExpression: // <
  574. methodName = "op_LessThan";
  575. break;
  576. case SyntaxKind.LessThanOrEqualExpression: // <=
  577. methodName = "op_LessThanOrEqual";
  578. break;
  579. case SyntaxKind.GreaterThanExpression: // >
  580. methodName = "op_GreaterThan";
  581. break;
  582. case SyntaxKind.GreaterThanOrEqualExpression: // >=
  583. methodName = "op_GreaterThanOrEqual";
  584. break;
  585. case SyntaxKind.UnaryMinusExpression: // unary -
  586. methodName = "op_UnaryNegation";
  587. break;
  588. case SyntaxKind.PreIncrementExpression: // ++a
  589. case SyntaxKind.PostIncrementExpression: // a++
  590. methodName = "op_Increment";
  591. break;
  592. case SyntaxKind.PreDecrementExpression: // --a
  593. case SyntaxKind.PostDecrementExpression: // a--
  594. methodName = "op_Decrement";
  595. break;
  596. default:
  597. throw new NotSupportedException("This operation isn't supported with this type");
  598. }
  599. return methodName;
  600. }
  601. private Type IsAsOp(BinaryExpressionSyntax binary, SyntaxKind kind)
  602. {
  603. var type1 = ParseToIL(binary.Left);
  604. var type2 = ParseToIL(binary.Right);
  605. Type returnType = type1;
  606. switch (kind)
  607. {
  608. case SyntaxKind.IsExpression: // is
  609. gen.Emit(OpCodes.Isinst, type2);
  610. gen.Emit(OpCodes.Ldnull);
  611. gen.Emit(OpCodes.Cgt_Un);
  612. returnType = typeof(bool);
  613. break;
  614. case SyntaxKind.AsExpression: // as
  615. // 'as' cannot be applied to non-reference types
  616. if (type2.IsValueType)
  617. throw new NotSupportedException();
  618. gen.Emit(OpCodes.Isinst, type2);
  619. returnType = type2;
  620. break;
  621. }
  622. return returnType;
  623. }
  624. private Type CastToGreaterType(Type leftType, Type rightType)
  625. {
  626. if (leftType == rightType)
  627. return leftType;
  628. Type result;
  629. result = CompareAndCastTo(leftType, rightType, typeof(Variant));
  630. if (result != null)
  631. return result;
  632. result = CompareAndCastTo(leftType, rightType, typeof(string)); // string is the strongest type
  633. if (result != null)
  634. return result;
  635. result = CompareAndCastTo(leftType, rightType, typeof(decimal));
  636. if (result != null)
  637. return result;
  638. result = CompareAndCastTo(leftType, rightType, typeof(double));
  639. if (result != null)
  640. return result;
  641. result = CompareAndCastTo(leftType, rightType, typeof(float));
  642. if (result != null)
  643. return result;
  644. result = CompareAndCastTo(leftType, rightType, typeof(ulong));
  645. if (result != null)
  646. return result;
  647. result = CompareAndCastTo(leftType, rightType, typeof(long));
  648. if (result != null)
  649. return result;
  650. throw new NotImplementedException();
  651. }
  652. private Type CompareAndCastTo(Type leftType, Type rightType, Type comparableType)
  653. {
  654. if (rightType == comparableType
  655. || leftType == comparableType)
  656. {
  657. if (leftType == comparableType)
  658. return CastTo(rightType, leftType);
  659. else
  660. return PreviousCastTo(leftType, rightType);
  661. }
  662. return null;
  663. }
  664. private Type PreviousCastTo(Type original, Type toType)
  665. {
  666. var local = gen.DeclareLocal(toType);
  667. gen.Emit(OpCodes.Stloc, local);
  668. // cast leftType:
  669. toType = CastTo(original, toType);
  670. gen.Emit(OpCodes.Ldloc, local);
  671. return toType;
  672. }
  673. private Type LogicalOp(BinaryExpressionSyntax binary, SyntaxKind kind)
  674. {
  675. var type1 = ParseToIL(binary.Left);
  676. Label answer = gen.DefineLabel();
  677. OpCode answerOpcode;
  678. Label next = gen.DefineLabel();
  679. switch (kind)
  680. {
  681. case SyntaxKind.LogicalOrExpression: // ||
  682. gen.Emit(OpCodes.Brtrue_S, answer);
  683. answerOpcode = OpCodes.Ldc_I4_1;
  684. break;
  685. case SyntaxKind.LogicalAndExpression: // &&
  686. gen.Emit(OpCodes.Brfalse_S, answer);
  687. answerOpcode = OpCodes.Ldc_I4_0;
  688. break;
  689. default: throw new Exception();
  690. }
  691. Type type2 = ParseToIL(binary.Right);
  692. gen.Emit(OpCodes.Br_S, next);
  693. gen.MarkLabel(answer);
  694. gen.Emit(answerOpcode);
  695. gen.MarkLabel(next);
  696. return typeof(bool);
  697. }
  698. private Type ExplicitCastOp(CastExpressionSyntax cast)
  699. {
  700. var originType = ParseToIL(cast.Expression);
  701. var type = ParseToIL(cast.Type);
  702. return CastTo(originType, type, true);
  703. }
  704. private Type CastTo(Type original, Type toType, bool _explicit = false)
  705. {
  706. if (original.IsClass)
  707. {
  708. if(toType.IsValueType)
  709. {
  710. if (original != typeof(object)) // Unbox only for object
  711. throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
  712. gen.Emit(OpCodes.Unbox_Any, toType);
  713. }
  714. else if (toType == typeof(object))
  715. return toType; // do nothing
  716. else
  717. gen.Emit(OpCodes.Castclass, toType);
  718. }
  719. else if (original.IsValueType)
  720. {
  721. if (toType == typeof(object))
  722. gen.Emit(OpCodes.Box, original);
  723. // decimal has special operators for parsing into different types (exclude object)
  724. else if (original == typeof(decimal))
  725. {
  726. var methods = original.GetMethods(BindingFlags.Static | BindingFlags.Public);
  727. foreach (var method in methods)
  728. if (method.ReturnType == toType && method.IsSpecialName)
  729. return MethodCall(original, method);
  730. }
  731. else if (toType == typeof(decimal))
  732. {
  733. var method = toType.GetMethod("op_Implicit", new Type[] { original });
  734. if (method != null)
  735. return MethodCall(toType, method);
  736. // float and double require explicit casting
  737. if (_explicit)
  738. {
  739. method = toType.GetMethod("op_Explicit", new Type[] { original });
  740. if (method != null)
  741. return MethodCall(toType, method);
  742. }
  743. throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
  744. }
  745. else if (toType == typeof(double))
  746. gen.Emit(OpCodes.Conv_R8);
  747. else if (toType == typeof(float))
  748. gen.Emit(OpCodes.Conv_R4);
  749. else if (toType == typeof(ulong))
  750. gen.Emit(OpCodes.Conv_U8);
  751. else if (toType == typeof(long))
  752. gen.Emit(OpCodes.Conv_I8);
  753. else if (toType.IsPrimitive)
  754. {
  755. // else int, uint etc
  756. // do nothing
  757. // TODO:
  758. // int + uint => long
  759. }
  760. else
  761. {
  762. var method = toType.GetMethod("op_Implicit", new Type[] { original });
  763. if (method != null)
  764. return MethodCall(toType, method);
  765. if (_explicit)
  766. {
  767. method = toType.GetMethod("op_Explicit", new Type[] { original });
  768. if (method != null)
  769. return MethodCall(toType, method);
  770. }
  771. if (toType.IsClass || toType.IsInterface)
  772. throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
  773. }
  774. }
  775. else if (original.IsInterface)
  776. {
  777. if (toType == typeof(object))
  778. return toType; // do nothing
  779. if (toType.IsValueType)
  780. {
  781. if (original.IsAssignableFrom(toType))
  782. throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
  783. gen.Emit(OpCodes.Unbox_Any, toType);
  784. }
  785. else
  786. gen.Emit(OpCodes.Castclass, toType);
  787. }
  788. else
  789. gen.Emit(OpCodes.Castclass, toType);
  790. return toType;
  791. }
  792. private Type CompareWithZero()
  793. {
  794. gen.Emit(OpCodes.Ldc_I4_0);
  795. gen.Emit(OpCodes.Ceq);
  796. return typeof(bool);
  797. }
  798. }
  799. }
  800. #endif