接 上篇的常量表達式的轉換,接下來要講的是怎麼產生操作運算表達式。
和C#通常意義上的3種操作符不同,我們的grammar把類型轉換操作()從unary expression裏拿出來獨立成一個typecast_expression,也就是說要轉換的操作符節點有4種。而且對於unary expression來說也有特別的地方,++,-- 這2個操作符不屬於unray_operator下,grammar是把它們獨立成pre_incr_decr_expression和post_incr_decr_expression 2塊單獨處理。還有就是在C#裏as這個操作符是被定義成一元的,而我們的grammar則視它爲二元操作符。
類型轉換的操作很簡單,這是grammar樹:
在這裏是做了一個int到int?的強類型轉換,所以可以看type_ref裏有一個qmark_opt,這表明是個nullable類型。
轉換入口:
case "typecast_expression":
return ProcessConvertExpression(expNode);
具體轉換代碼:
private Expression ProcessConvertExpression(ParseTreeNode expNode)
{
var type = expNode.GetChild("typecast_parenthesized_expression").GetClrType();
var exp = ProcessExpression(expNode.GetChild("primary_expression"));
return Expression.Convert(exp, type);
}
可以看到這裏爲了取到要被強類型轉換的對象,採用了遞歸調用ProcssExpression處理方式,而子節點裏是一個literal,所以子節點會返回一個ConstantExpression。而GetClrType是treenode的擴展方法,它的代碼在第一章裏有提到。
public static Type GetClrType(this ParseTreeNode node)
{
if (node.HasChild("type_ref"))
{
var isNullable = node.GetDescendant("qmark_opt").FindTokenAndGetText() == "?";
var typeName = node.FindTokenAndGetText();
var type = ExpressionParser.GetType(typeName);
if (isNullable)
return typeof(Nullable<>).MakeGenericType(type);
return type;
}
return null;
}
就是根據type_ref子節點返回正確的clr類型。其中ExpressionParser.GetType方法如下:
internal static Type GetType(string typeName)
{
var type = Type.GetType(typeName);
if (type == null)
knownTypes.TryGetValue(typeName, out type);
return type;
}
就是通過typename得到Type,這裏要注意的是int、char、string這些內建類型的名字並不是int、char、string,所以會有個knownTypes表來幫助返回正確的類型:
private static ConcurrentDictionary<string, Type> knownTypes = new ConcurrentDictionary<string, Type>();
#region BuiltinTypes
knownTypes["bool"] = typeof(bool);
knownTypes["sbyte"] = typeof(sbyte);
knownTypes["byte"] = typeof(byte);
knownTypes["short"] = typeof(short);
knownTypes["ushort"] = typeof(ushort);
knownTypes["int"] = typeof(int);
knownTypes["uint"] = typeof(uint);
knownTypes["long"] = typeof(long);
knownTypes["ulong"] = typeof(ulong);
knownTypes["float"] = typeof(float);
knownTypes["double"] = typeof(double);
knownTypes["char"] = typeof(char);
knownTypes["string"] = typeof(string);
knownTypes["decimal"] = typeof(decimal);
knownTypes["object"] = typeof(object);
knownTypes["void"] = typeof(void);
#endregion
正確的類型和正確的對象,創建個ConvertExpression也就非常簡單了