public object Visit(ParameterExpression parameter) { return(new XsParameter(parameter.Name, ctx.GetClrType(parameter.Type))); }
private object ArithmethicOperation(BinaryExpression binaryOp, OpCode op, XzaarType resultType = null) { if (resultType == null) { resultType = XzaarBaseTypes.Number; } var il = ctx.GetILGenerator(); if (resultType.Name == "string") { // determine which side is a string var leftType = binaryOp.Left.Type; var rightType = binaryOp.Right.Type; var boxLeft = false; var boxRight = false; // if both are strings, we can just find the normal string,string concat function and call that one. // if one of the types are a valuetype (not a class or 'any'), then that type needs to be boxed // then use the object,object concat function instead MethodInfo targetConcatMethod = typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }); if (leftType.Name == "string") { if (rightType.Name == "string") { targetConcatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) }); } else { #warning Concating string requires struct's to be boxed. TODO: Add boxing for structs! boxRight = rightType.IsNumeric; // numbers and structs needs to be boxed, right now we don't know if one is a struct or not // check if boxing is necessary on the 'right' type. } } else { boxLeft = leftType.IsNumeric; // check if boxing is necessary on the 'left' type. } var l = Visit(binaryOp.Left); TryLoadReference(l, il); if (boxLeft) { il.Box(ctx.GetClrType(leftType)); } var r = Visit(binaryOp.Right); TryLoadReference(r, il); if (boxRight) { il.Box(ctx.GetClrType(rightType)); } il.Call(targetConcatMethod); return(true); } // NOTE: arithmetic operations does NOT necessarily have to introduce a // temporary variable, but COULD. I decided to skip it for simplicity var left = Visit(binaryOp.Left); TryLoadReference(left, il); // if its not any of the ones above, it must be either a function call or constant var right = Visit(binaryOp.Right); TryLoadReference(right, il); il.Emit(op); return(true); }