BoundExpression BindSimpleVarUse(AST.SimpleVarUse expr, BoundAccess access) { var dexpr = expr as AST.DirectVarUse; var iexpr = expr as AST.IndirectVarUse; Debug.Assert(dexpr != null || iexpr != null); var varname = (dexpr != null) ? new BoundVariableName(dexpr.VarName) : new BoundVariableName(BindExpression(iexpr.VarNameEx)); if (expr.IsMemberOf == null) { return(new BoundVariableRef(varname)); } else { var instanceAccess = BoundAccess.Read; if (access.IsWrite || access.EnsureObject || access.EnsureArray) { instanceAccess = instanceAccess.WithEnsureObject(); } if (access.IsQuiet) { instanceAccess = instanceAccess.WithQuiet(); } return(BoundFieldRef.CreateInstanceField(BindExpression(expr.IsMemberOf, instanceAccess), varname).WithAccess(access)); } }
BoundExpression BindConstUse(AST.ConstantUse x) { if (x is AST.GlobalConstUse) { return(BindGlobalConstUse((AST.GlobalConstUse)x)); } if (x is AST.ClassConstUse) { var cx = (AST.ClassConstUse)x; var typeref = BindTypeRef(cx.TargetType); if (cx.Name.Equals("class")) // pseudo class constant { return(new BoundPseudoClassConst(typeref, AST.PseudoClassConstUse.Types.Class)); } return(BoundFieldRef.CreateClassConst(typeref, new BoundVariableName(cx.Name))); } throw ExceptionUtilities.UnexpectedValue(x); }
BoundExpression BindConstUse(AST.ConstantUse x) { if (x is AST.GlobalConstUse) { return(BindGlobalConstUse((AST.GlobalConstUse)x)); } if (x is AST.ClassConstUse) { var cx = (AST.ClassConstUse)x; var dtype = cx.TypeRef as AST.DirectTypeRef; if (dtype != null && cx.Name.Equals("class")) // Type::class ~ "Type" { return(new BoundLiteral(dtype.ClassName.ToString())); } var typeref = BindTypeRef(cx.TypeRef); return(BoundFieldRef.CreateClassConst(typeref, new BoundVariableName(cx.Name))); } throw ExceptionUtilities.UnexpectedValue(x); }
BoundExpression BindFieldUse(AST.StaticFieldUse x, BoundAccess access) { var typeref = BindTypeRef(x.TypeRef); BoundVariableName varname; if (x is AST.DirectStFldUse) { var dx = (AST.DirectStFldUse)x; varname = new BoundVariableName(dx.PropertyName); } else if (x is AST.IndirectStFldUse) { var ix = (AST.IndirectStFldUse)x; var fieldNameExpr = BindExpression(ix.FieldNameExpr, BoundAccess.Read); varname = new BoundVariableName(fieldNameExpr); } else { throw ExceptionUtilities.UnexpectedValue(x); } return(BoundFieldRef.CreateStaticField(typeref, varname)); }
public virtual void VisitFieldRef(BoundFieldRef x) { VisitTypeRef(x.ParentType); Accept(x.Instance); Accept(x.FieldName.NameExpression); }
public virtual TResult VisitFieldRef(BoundFieldRef x) => DefaultVisitOperation(x);
public BoundIndirectStFieldPlace(BoundTypeRef typeref, BoundVariableName fldname, BoundFieldRef boundref) { _type = typeref; _name = fldname; _boundref = boundref; }
public virtual void VisitFieldRef(BoundFieldRef x) { }
public override void VisitFieldRef(BoundFieldRef x) { Accept(x.Instance); VisitTypeRef(x.ParentType); Accept(x.FieldName.NameExpression); if (x.IsInstanceField) // {Instance}->FieldName { Debug.Assert(x.Instance != null); Debug.Assert(x.Instance.Access.IsRead); // resolve field if possible var typerefs = TypeCtx.GetTypes(x.Instance.TypeRefMask); if (typerefs.Count == 1 && typerefs[0].IsObject) { // TODO: x.Instance.ResultType instead of following var t = (NamedTypeSymbol)_model.GetType(typerefs[0].QualifiedName); if (t != null) { if (x.FieldName.IsDirect) { // TODO: visibility and resolution (model) var field = t.LookupMember<FieldSymbol>(x.FieldName.NameValue.Value); if (field != null) { x.BoundReference = new BoundFieldPlace(x.Instance, field, x); x.TypeRefMask = field.GetResultType(TypeCtx); return; } else { var prop = t.LookupMember<PropertySymbol>(x.FieldName.NameValue.Value); if (prop != null) { x.BoundReference = new BoundPropertyPlace(x.Instance, prop); x.TypeRefMask = TypeRefFactory.CreateMask(TypeCtx, prop.Type); return; } else { // TODO: use runtime fields directly, __get, __set, etc., // do not fallback to BoundIndirectFieldPlace } } } } } // dynamic behavior // indirect field access ... x.BoundReference = new BoundIndirectFieldPlace(x.Instance, x.FieldName, x.Access); x.TypeRefMask = TypeRefMask.AnyType; return; } // static fields or constants if (x.IsStaticField || x.IsClassConstant) // {ClassName}::${StaticFieldName}, {ClassName}::{ConstantName} { var ParentType = (NamedTypeSymbol)x.ParentType.ResolvedType; if (x.IsClassConstant) { Debug.Assert(x.Access.IsRead); Debug.Assert(!x.Access.IsEnsure && !x.Access.IsWrite && !x.Access.IsReadRef); } if (ParentType != null && x.FieldName.IsDirect) { var fldname = x.FieldName.NameValue.Value; var field = x.IsStaticField ? ParentType.ResolveStaticField(fldname) : ParentType.ResolveClassConstant(fldname); if (field != null) { // TODO: visibility -> ErrCode Debug.Assert( field.IsConst || // .NET constant field.IsStatic || // .NET static field.ContainingType.TryGetStatics().LookupMember<FieldSymbol>(x.FieldName.NameValue.Value) != null); // or PHP context static if (BindConstantValue(x, field)) { Debug.Assert(x.Access.IsRead && !x.Access.IsWrite && !x.Access.IsEnsure); x.BoundReference = null; // not reachable } else { x.BoundReference = field.IsStatic ? new BoundFieldPlace(null, field, x) // the field is real .NET static member (CLR static fields) : new BoundPhpStaticFieldPlace(field, x); // the field is contained in special __statics container (fields & constants) } x.TypeRefMask = field.GetResultType(TypeCtx); return; } else if (x.IsStaticField) { // TODO: visibility var prop = ParentType.LookupMember<PropertySymbol>(fldname); if (prop != null && prop.IsStatic) { x.BoundReference = new BoundPropertyPlace(null, prop); x.TypeRefMask = TypeRefFactory.CreateMask(TypeCtx, prop.Type); return; } } // TODO: __getStatic, __setStatic } // indirect field access: // indirect field access with known class name: x.BoundReference = new BoundIndirectStFieldPlace(x.ParentType, x.FieldName, x); x.TypeRefMask = TypeRefMask.AnyType; return; } }