public PhpParam(TypeRefMask tmask, bool isByRef, bool isVariadic, BoundExpression defaultValue) { this.Type = tmask; this.IsVariadic = isVariadic; this.DefaultValue = defaultValue; this.IsByRef = isByRef; }
/// <summary> /// If possible, gets <see cref="IPlace"/> representing given expression (in case of a field or variable). /// </summary> /// <param name="expr"></param> /// <returns>Place or <c>null</c>.</returns> internal IPlace PlaceOrNull(BoundExpression expr) { if (expr is BoundReferenceExpression) { return ((BoundReferenceExpression)expr).Place(_il); } return null; }
public SourceFieldSymbol(SourceTypeSymbol type, string name, Accessibility accessibility, PHPDocBlock phpdoc, KindEnum kind, BoundExpression initializer = null) { Contract.ThrowIfNull(type); Contract.ThrowIfNull(name); _containingType = type; _fieldName = name; _fieldKind = kind; _accessibility = accessibility; _phpDoc = phpdoc; _initializer = initializer; }
public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int index, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(index >= 0); _routine = routine; _syntax = syntax; _index = index; _ptagOpt = ptagOpt; _initializer = (syntax.InitValue != null) ? new SemanticsBinder(null).BindExpression(syntax.InitValue, BoundAccess.Read) : null; }
/// <summary> /// Handles use of variable as foreach iterator value. /// </summary> /// <param name="varuse"></param> /// <returns>Derivate type of iterated values.</returns> protected virtual TypeRefMask HandleTraversableUse(BoundExpression/*!*/varuse) { return TypeRefMask.AnyType; }
/// <summary> /// Emits comparison operator pushing <c>bool</c> (<c>i4</c> of value <c>0</c> or <c>1</c>) onto the evaluation stack. /// </summary> /// <returns>Resulting type code pushed onto the top of evaliuation stack.</returns> internal static TypeSymbol EmitLtGt(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, bool lt) { TypeSymbol ytype; var il = cg.Builder; switch (xtype.SpecialType) { case SpecialType.System_Void: // Operators.CompareNull(value) throw new NotImplementedException(); case SpecialType.System_Int32: // i4 -> i8 il.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.Operators.Clt_long_double : cg.CoreMethods.Operators.Cgt_long_double); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) <> 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 <> r8 il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else { // compare(r8, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string); } else if (ytype.SpecialType == SpecialType.System_Int64) { // compare(string, long) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // compare(string, double) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_double); } else { // compare(string, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); } // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; case SpecialType.System_Boolean: cg.EmitConvert(right, cg.CoreTypes.Boolean); ytype = cg.CoreTypes.Boolean; // compare(bool, bool) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_bool_bool); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { // number <> i8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_long : cg.CoreMethods.PhpNumber.gt_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_double : cg.CoreMethods.PhpNumber.gt_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number <> number return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_number : cg.CoreMethods.PhpNumber.gt_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(number, value) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_number_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); // +1 on stack il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } else { xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); // TODO: if (ytype.SpecialType == SpecialType.System_Boolean) ... // TODO: if (ytype.SpecialType == SpecialType.System_Int64) ... // TODO: if (ytype.SpecialType == SpecialType.System_String) ... // TODO: if (ytype.SpecialType == SpecialType.System_Double) ... // compare(value, value) ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_value_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } }
/// <summary> /// Emits subtraction operator. /// </summary> internal static TypeSymbol EmitSub(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // i8 - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_double) .Expect(cg.CoreTypes.Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_number) .Expect(cg.CoreTypes.PhpNumber); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // i8 - value : value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_value) .Expect(cg.CoreTypes.PhpNumber); } case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 - r8 : r8 il.EmitOpCode(ILOpCode.Sub); return cg.CoreTypes.Double; } throw new NotImplementedException($"Sub(double, {ytype.Name})"); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // number - r8 : double return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // number - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_number) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpNumber, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // value - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // value - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // value - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // value - value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_value) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpValue, {ytype.Name})"); } throw new NotImplementedException($"Sub({xtype.Name},...)"); } }
internal static TypeSymbol EmitBitOr(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { switch (xtype.SpecialType) { case SpecialType.System_Void: case SpecialType.System_Int32: case SpecialType.System_Boolean: case SpecialType.System_Double: cg.EmitConvert(xtype, 0, cg.CoreTypes.Long); goto case SpecialType.System_Int64; case SpecialType.System_Int64: cg.EmitConvert(right, cg.CoreTypes.Long); cg.Builder.EmitOpCode(ILOpCode.Or); return cg.CoreTypes.Long; case SpecialType.System_String: throw new NotImplementedException(); // string | string or string | long default: if (right.ResultType != null && right.ResultType.SpecialType != SpecialType.System_String) { // value | !string -> long | long -> long cg.EmitConvert(xtype, 0, cg.CoreTypes.Long); goto case SpecialType.System_Int64; } cg.EmitConvert(xtype, 0, cg.CoreTypes.PhpValue); cg.EmitConvert(right, cg.CoreTypes.PhpValue); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BitwiseOr_PhpValue_PhpValue) .Expect(cg.CoreTypes.PhpValue); } }
/// <summary> /// Emits <c>+</c> operator suitable for actual operands. /// </summary> private static TypeSymbol EmitAdd(CodeGenerator cg, BoundExpression left, BoundExpression right, TypeSymbol resultTypeOpt = null) { // Template: x + y return EmitAdd(cg, cg.Emit(left), right, resultTypeOpt); }
static TypeSymbol EmitAppend(CodeGenerator cg, TypeSymbol xtype, BoundExpression y) { if (xtype == cg.CoreTypes.PhpString) { // x.Append(y); return x; cg.Builder.EmitOpCode(ILOpCode.Dup); cg.EmitConvert(y, cg.CoreTypes.String); cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_String); // return xtype; } else { // concat(x, y) cg.EmitConvert(xtype, 0, cg.CoreTypes.String); cg.EmitConvert(y, cg.CoreTypes.String); return cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString_string_string); } }
/// <summary> /// Emits instance. Caches the result if holder is provided, or loads evaluated instance if holder was initialized already. /// </summary> public static TypeSymbol EmitInstance(InstanceCacheHolder holderOrNull, CodeGenerator cg, BoundExpression instance) { return (instance != null) ? EmitInstance(holderOrNull, cg, () => cg.Emit(instance)) : null; }
internal static TypeSymbol EmitPow(CodeGenerator cg, TypeSymbol xtype, FlowAnalysis.TypeRefMask xtype_hint, BoundExpression right) { var il = cg.Builder; TypeSymbol ytype; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> long switch (xtype.SpecialType) { case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype.SpecialType == SpecialType.System_Int64) { // i8 ** i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_number); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // i8 ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_value); case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // int|bool|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_double); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // r8 ** value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_value); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype == cg.CoreTypes.Double) { // number ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_double); } if (ytype.SpecialType == SpecialType.System_Int64) { // y -> number ytype = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Create_Long); } if (ytype == cg.CoreTypes.PhpNumber) { // number ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_number); } // y -> PhpValue ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); // number ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_value); } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, xtype_hint); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_value_value); } }
public BoundPhpStaticFieldPlace(FieldSymbol field, BoundExpression boundref) : base(null, field, boundref) { Debug.Assert(!field.IsStatic); Debug.Assert(field.ContainingType.TryGetStatics() != null); }
public BoundIndirectFieldPlace(BoundExpression instance, BoundVariableName name, BoundAccess access) { Contract.ThrowIfNull(name); _instance = instance; _name = name; _access = access; }
public BoundFieldPlace(BoundExpression instance, FieldSymbol field, BoundExpression boundref) { Contract.ThrowIfNull(field); _instance = instance; _field = field; _boundref = boundref; }
public BoundPropertyPlace(BoundExpression instance, Cci.IPropertyDefinition property) { Contract.ThrowIfNull(property); _instance = instance; _property = (PropertySymbol)property; }
public BoundGlobalPlace(BoundExpression nameExpr, BoundAccess access) : base(nameExpr, access) { }
internal static TypeSymbol EmitMul(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 * r8 : r8 il.EmitOpCode(ILOpCode.Mul); return xtype; // r8 } else if (ytype == cg.CoreTypes.PhpValue) { // r8 * value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_double_value) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Mul(double, {ytype.Name})"); case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // i8 * i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 * r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 * number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // i8 * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Mul(int64, {ytype.Name})"); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_double) .Expect(cg.CoreTypes.Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // number * number : number cg.EmitConvertToPhpNumber(ytype, right.TypeRefMask); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // number * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_value) .Expect(cg.CoreTypes.PhpNumber); } else { // TODO: unconvertible // number * number : number cg.EmitConvertToPhpNumber(ytype, right.TypeRefMask); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_number) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Mul(PhpNumber, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpValue) { // value * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_value) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpNumber) { // value * number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.Long) { // value * i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.Double) { // value * r8 : double return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_double) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Mul(PhpValue, {ytype.Name})"); } // throw new NotImplementedException($"Mul({xtype.Name}, ...)"); } }
/// <summary> /// Emits name as string. Caches the result if holder is provided, or loads evaluated name if holder was initialized already. /// </summary> public static void EmitName(InstanceCacheHolder holderOrNull, CodeGenerator cg, BoundExpression name) { Contract.ThrowIfNull(cg); Contract.ThrowIfNull(name); if (holderOrNull != null) { holderOrNull.EmitName(cg, name); } else { cg.EmitConvert(name, cg.CoreTypes.String); } }
internal static TypeSymbol EmitDiv(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { il.EmitOpCode(ILOpCode.Div); return xtype; // r8 } // double / value : double cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_double_PhpValue); case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // long / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_long_number) .Expect(cg.CoreTypes.PhpNumber); } // long / value : number cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_long_PhpValue); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // nmumber / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_number_number) .Expect(cg.CoreTypes.PhpNumber); } } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, 0); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value / value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_PhpValue_PhpValue); } }
/// <summary> /// Emits name as string, uses cached variable. /// </summary> void EmitName(CodeGenerator cg, BoundExpression name) { Contract.ThrowIfNull(cg); Contract.ThrowIfNull(name); if (_name_loc != null) { cg.Builder.EmitLocalLoad(_name_loc); } else { _cg = cg; // return (<loc> = <name>) _name_loc = cg.GetTemporaryLocal(cg.CoreTypes.String); cg.EmitConvert(name, cg.CoreTypes.String); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(_name_loc); } }
bool IsEmpty(BoundExpression x) { if (x.ConstantValue.HasValue) { var value = x.ConstantValue.Value; if (value == null) return true; if (value is string && ((string)value).Length == 0) return true; if (value is bool && ((bool)value) == false) return true; } return false; }
public BoundIndirectVariablePlace(BoundExpression nameExpr, BoundAccess access) { Contract.ThrowIfNull(nameExpr); _nameExpr = nameExpr; _access = access; }
/// <summary> /// Emits <c>+</c> operator suitable for actual operands. /// </summary> internal static TypeSymbol EmitAdd(CodeGenerator cg, TypeSymbol xtype, BoundExpression Right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> long // if (xtype == cg.CoreTypes.PhpNumber) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long if (ytype == cg.CoreTypes.PhpNumber) { // number + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // number + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_double) .Expect(SpecialType.System_Double); } else if (ytype.SpecialType == SpecialType.System_Int64) { // number + long : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // number + value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Add(number, {ytype.Name})"); } else if (xtype.SpecialType == SpecialType.System_Double) { var ytype = cg.EmitConvertNumberToDouble(Right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 + r8 : r8 il.EmitOpCode(ILOpCode.Add); return cg.CoreTypes.Double; } else if (ytype == cg.CoreTypes.PhpValue) { // r8 + value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_double_value) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Add(double, {ytype.Name})"); } else if (xtype.SpecialType == SpecialType.System_Int64) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long if (ytype.SpecialType == SpecialType.System_Int64) { if (resultTypeOpt != null) { if (resultTypeOpt.SpecialType == SpecialType.System_Int64) { // (long)(i8 + i8 : number) il.EmitOpCode(ILOpCode.Add); return cg.CoreTypes.Long; } } // i8 + i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // i8 + value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Add(int64, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long // PhpString -> String if (ytype == cg.CoreTypes.PhpString) { cg.EmitConvertToString(ytype, 0); // continue ... } if (ytype.SpecialType == SpecialType.System_Int64) { // value + i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // value + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.String) { // value + string : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_string) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpNumber) { // value + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // value + value : value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_value) .Expect(cg.CoreTypes.PhpValue); } // throw new NotImplementedException($"Add(PhpValue, {ytype.Name})"); } // throw new NotImplementedException($"Add({xtype.Name}, ...)"); }
internal static TypeSymbol EmitStrictEquality(CodeGenerator cg, BoundExpression left, BoundExpression right) => EmitStrictEquality(cg, cg.Emit(left), right);
/// <summary> /// Emits subtraction operator. /// </summary> internal static TypeSymbol EmitSub(CodeGenerator cg, BoundExpression left, BoundExpression right, TypeSymbol resultTypeOpt = null) { return EmitSub(cg, cg.Emit(left), right, resultTypeOpt); }
internal BoundParameter(ParameterSymbol symbol, BoundExpression initializer) : base(VariableKind.Parameter) { _symbol = symbol; _initializer = initializer; }
internal static TypeSymbol EmitBitOr(CodeGenerator cg, BoundExpression left, BoundExpression right) { // most common cases: if (cg.IsLongOnly(left.TypeRefMask) || cg.IsLongOnly(right.TypeRefMask)) { // i64 | i64 : i64 cg.EmitConvert(left, cg.CoreTypes.Long); cg.EmitConvert(right, cg.CoreTypes.Long); cg.Builder.EmitOpCode(ILOpCode.Or); return cg.CoreTypes.Long; } // return EmitBitOr(cg, cg.Emit(left), right); }
public BoundIndirectLocal(BoundExpression nameExpr) : base(VariableKind.LocalVariable) { _nameExpr = nameExpr; }
/// <summary> /// Emits check for values equality. /// Lefts <c>bool</c> on top of evaluation stack. /// </summary> internal static TypeSymbol EmitEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: // bool == y.ToBoolean() cg.EmitConvert(right, cg.CoreTypes.Boolean); cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; case SpecialType.System_Int32: // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.Emit(right); // if (ytype.SpecialType == SpecialType.System_Int32) { cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 ytype = cg.CoreTypes.Long; } // if (ytype.SpecialType == SpecialType.System_Int64) { // i8 == i8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // i8 == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // i8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|long|int -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_String) { // r8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_double_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(double, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Int32) { // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); ytype = cg.CoreTypes.Long; } if (ytype.SpecialType == SpecialType.System_Int64) { // string == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // string == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // string == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string).Expect(SpecialType.System_Int32); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(string, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; //case SpecialType.System_Object: // goto default; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number == number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // number == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_PhpValue) .Expect(SpecialType.System_Boolean); } } else { // TODO: xtype: PhpArray, ... xtype = cg.EmitConvertToPhpValue(xtype, 0); // TODO: overloads for type of <right> ytype = cg.EmitConvertToPhpValue(cg.Emit(right), right.TypeRefMask); // value == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Eq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
/// <summary> /// Visits condition used to branch execution to true or false branch. /// </summary> /// <remarks> /// Because of minimal evaluation there is different FlowState for true and false branches, /// AND and OR operators have to take this into account. /// /// Also some other constructs may have side-effect for known branch, /// eg. <c>($x instanceof X)</c> implies ($x is X) in True branch. /// </remarks> internal void VisitCondition(BoundExpression condition, ConditionBranch branch) { Contract.ThrowIfNull(condition); if (branch != ConditionBranch.AnyResult) { if (condition is BoundBinaryEx) { Visit((BoundBinaryEx)condition, branch); return; } if (condition is BoundUnaryEx) { Visit((BoundUnaryEx)condition, branch); return; } //if (condition is DirectFcnCall) //{ // VisitDirectFcnCall((DirectFcnCall)condition, branch); // return; //} if (condition is BoundInstanceOfEx) { Visit((BoundInstanceOfEx)condition, branch); return; } //if (condition is IssetEx) //{ // VisitIssetEx((IssetEx)condition, branch); // return; //} //if (condition is EmptyEx) //{ // VisitEmptyEx((EmptyEx)condition, branch); // return; //} } // no effect condition.Accept(this); }
internal static TypeSymbol EmitStrictEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // bool == bool cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Double || ytype.SpecialType == SpecialType.System_Int32 || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_String || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.PhpString || ytype == cg.CoreTypes.Object) { // bool == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // bool == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_bool_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Int32: cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Int32) { cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 ytype = cg.CoreTypes.Long; } if (ytype.SpecialType == SpecialType.System_Int64) { // i8 == i8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Double || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // i8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // i8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_long_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Double: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_Int32 || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // r8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // r8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_double_PhpValue) .Expect(SpecialType.System_Boolean); } default: // TODO: PhpArray, Object === ... xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // PhpValue == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_bool) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // PhpValue == PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
/// <summary> /// Returns whether the expression has constant value. /// </summary> public static bool IsConstant(this BoundExpression expr) => expr.ConstantValue.HasValue;