Skip to content

Commit

Permalink
binding callable convert, not implemented yet
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubmisek committed Feb 23, 2025
1 parent 462eecb commit 59abe71
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 22 deletions.
15 changes: 9 additions & 6 deletions src/Peachpie.CodeAnalysis/CodeGen/Graph/BoundExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2351,6 +2351,14 @@ internal override TypeSymbol Emit(CodeGenerator cg)
}

partial class BoundCallableConvert
{
internal override TypeSymbol Emit(CodeGenerator cg)
{
throw new NotImplementedException();
}
}

partial class BoundConvertToCallable
{
internal override TypeSymbol Emit(CodeGenerator cg)
{
Expand Down Expand Up @@ -3384,7 +3392,7 @@ internal override TypeSymbol Emit(CodeGenerator cg)

cg.EmitLoadContext(); // Context
idxfld.EmitLoad(cg); // routine
EmitThis(cg); // $this
cg.EmitPhpThisOrNull(); // $this
cg.EmitCallerTypeHandle(); // scope
EmitStaticType(cg); // statictype : PhpTypeInfo
EmitCachedParametersArray(cg, ((LambdaFunctionExpr)PhpSyntax).Signature.FormalParamsFixed()); // "parameters"
Expand All @@ -3393,11 +3401,6 @@ internal override TypeSymbol Emit(CodeGenerator cg)
return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BuildClosure_Context_IPhpCallable_Object_RuntimeTypeHandle_PhpTypeInfo_PhpArray_PhpArray);
}

void EmitThis(CodeGenerator cg)
{
cg.EmitPhpThisOrNull();
}

void EmitStaticType(CodeGenerator cg)
{
if ((cg.Routine.Flags & FlowAnalysis.RoutineFlags.UsesLateStatic) != 0)
Expand Down
7 changes: 7 additions & 0 deletions src/Peachpie.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,13 @@ public override T VisitConversion(BoundConversionEx x)
return default;
}

public override T VisitCallableConvert(BoundCallableConvert x)
{
x.TypeRefMask = TypeCtx.GetClosureTypeMask();

return base.VisitCallableConvert(x);
}

#endregion

#region Visit InstanceOf
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ public override object VisitLiteral(BoundLiteral x)
{
TransformationCount++;
x.Access = x.Access.WithRead(DeclaringCompilation.CoreTypes.String); // read the literal as string, do not rewrite it to BoundCallableConvert again
return new BoundCallableConvert(x, DeclaringCompilation) { TargetCallable = symbol }.WithContext(x);
return new BoundConvertToCallable(x, DeclaringCompilation) { TargetCallable = symbol }.WithContext(x);
}
}

Expand Down Expand Up @@ -813,13 +813,13 @@ bool TryGetMethod(TypeSymbol typeSymbol, string methodName, out MethodSymbol met
}
}

BoundCallableConvert Transform(BoundArrayEx origArray, IMethodSymbol targetCallable, BoundExpression receiver = null)
BoundConvertToCallable Transform(BoundArrayEx origArray, IMethodSymbol targetCallable, BoundExpression receiver = null)
{
// read the literal as array, do not rewrite it to BoundCallableConvert again
origArray.Access = origArray.Access.WithRead(DeclaringCompilation.CoreTypes.PhpArray);

TransformationCount++;
return new BoundCallableConvert(origArray, DeclaringCompilation)
return new BoundConvertToCallable(origArray, DeclaringCompilation)
{
TargetCallable = targetCallable,
Receiver = receiver
Expand Down
87 changes: 84 additions & 3 deletions src/Peachpie.CodeAnalysis/Semantics/BoundExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ internal BoundConversionEx(BoundExpression operand, BoundTypeRef targetType)
this.TargetType = targetType ?? throw ExceptionUtilities.ArgumentNull(nameof(targetType));
}

internal BoundConversionEx Update(BoundExpression operand, BoundTypeRef targetType)
internal virtual BoundConversionEx Update(BoundExpression operand, BoundTypeRef targetType)
{
if (operand == this.Operand && targetType == this.TargetType)
{
Expand All @@ -1379,7 +1379,7 @@ internal BoundConversionEx Update(BoundExpression operand, BoundTypeRef targetTy
}

/// <summary>
/// Conversion to <c>IPhpCallable</c> (callable).
/// Callable convert syntax.
/// </summary>
public partial class BoundCallableConvert : BoundConversionEx
{
Expand All @@ -1391,10 +1391,91 @@ public partial class BoundCallableConvert : BoundConversionEx
/// <summary>In case of an instance method, this is its receiver instance.</summary>
internal BoundExpression Receiver { get; set; }

internal BoundCallableConvert(BoundExpression operand, PhpCompilation compilation)
/// <summary>In case of a static method, this is its receiver type.</summary>
internal IBoundTypeRef StaticReceiver { get; set; }

/// <summary>
/// Bound function name in case it's callable convert.
/// </summary>
internal BoundRoutineName Name { get; set; }

internal BoundCallableConvert(BoundExpression receiver, BoundRoutineName name, PhpCompilation compilation)
: this(new BoundLiteral(null), compilation)
{
this.Receiver = receiver;
this.Name = name;
}

internal BoundCallableConvert(IBoundTypeRef receiver, BoundRoutineName name, PhpCompilation compilation)
: this(new BoundLiteral(null), compilation)
{
this.StaticReceiver = receiver;
this.Name = name;
}

private BoundCallableConvert(BoundExpression operand, PhpCompilation compilation)
: base(operand, compilation.TypeRefFactory.Create(compilation.CoreTypes.IPhpCallable.Symbol))
{
}

internal override BoundConversionEx Update(BoundExpression operand, BoundTypeRef targetType)
{
throw ExceptionUtilities.Unreachable;

//if (operand == this.Operand && targetType == this.TargetType)
//{
// return this;
//}
//else
//{
// return new BoundCallableConvert(operand, targetType).WithContext(this);
//}
}

public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument) => visitor.VisitConversion(this, argument);

public override TResult Accept<TResult>(PhpOperationVisitor<TResult> visitor) => visitor.VisitCallableConvert(this);
}

/// <summary>
/// Conversion to <c>IPhpCallable</c> (callable).
/// </summary>
public partial class BoundConvertToCallable : BoundConversionEx
{
/// <summary>
/// Resolved method to be converted to callable.
/// </summary>
public IMethodSymbol TargetCallable { get; internal set; }

/// <summary>In case of an instance method, this is its receiver instance.</summary>
internal BoundExpression Receiver { get; set; }

internal BoundConvertToCallable(BoundExpression operand, PhpCompilation compilation)
: this(operand, compilation.TypeRefFactory.Create(compilation.CoreTypes.IPhpCallable.Symbol))
{
}

private BoundConvertToCallable(BoundExpression operand, BoundTypeRef targetType)
: base(operand, targetType)
{

}

internal override BoundConversionEx Update(BoundExpression operand, BoundTypeRef targetType)
{
if (operand == this.Operand && targetType == this.TargetType)
{
return this;
}
else
{
return new BoundConvertToCallable(operand, targetType)
{
TargetCallable = TargetCallable,
Receiver = Receiver,
}.WithContext(this);
}
}
}

#endregion
Expand Down
2 changes: 2 additions & 0 deletions src/Peachpie.CodeAnalysis/Semantics/PhpOperationVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public abstract class PhpOperationVisitor<TResult>

public virtual TResult VisitConversion(BoundConversionEx x) => DefaultVisitOperation(x);

public virtual TResult VisitCallableConvert(BoundCallableConvert x) => DefaultVisitOperation(x);

public virtual TResult VisitIncDec(BoundIncDecEx x) => DefaultVisitOperation(x);

public virtual TResult VisitConditional(BoundConditionalEx x) => DefaultVisitOperation(x);
Expand Down
32 changes: 22 additions & 10 deletions src/Peachpie.CodeAnalysis/Semantics/SemanticsBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -820,12 +820,6 @@ protected BoundExpression BindFunctionCall(AST.FunctionCall x, BoundExpression b
boundTarget = BindIsMemberOfChain(x.IsMemberOf, BoundAccess.Read/*Object?*/);
}

// callable convert syntax (...)
if (x.CallSignature.IsCallableConvert)
{
throw new NotImplementedException("callable convert");
}

BoundRoutineCall result;

if (x is AST.DirectFcnCall)
Expand All @@ -835,6 +829,11 @@ protected BoundExpression BindFunctionCall(AST.FunctionCall x, BoundExpression b

var fname = ((AST.DirectFcnCall)x).FullName;

if (x.CallSignature.IsCallableConvert) // callable convert syntax (...)
{
return new BoundCallableConvert(boundTarget, new BoundRoutineName(fname.Name), DeclaringCompilation);
}

if (boundTarget == null)
{
if (fname.IsGetArgsOrArgsNumFunctionName() && Routine != null)
Expand Down Expand Up @@ -863,15 +862,22 @@ protected BoundExpression BindFunctionCall(AST.FunctionCall x, BoundExpression b
{
Debug.Assert(fname.FallbackName.HasValue == false);
Debug.Assert(fname.Name.QualifiedName.IsSimpleName);

result = new BoundInstanceFunctionCall(boundTarget, fname.Name, BindArguments(x.CallSignature.Parameters));
}
}
else if (x is AST.IndirectFcnCall)
else if (x is AST.IndirectFcnCall indirect)
{
// $func(...)
// $x->$func(...)

var nameExpr = BindExpression(((AST.IndirectFcnCall)x).NameExpr);
var nameExpr = BindExpression(indirect.NameExpr);

if (x.CallSignature.IsCallableConvert) // callable convert syntax (...)
{
return new BoundCallableConvert(boundTarget, new BoundRoutineName(nameExpr), DeclaringCompilation);
}

if (boundTarget == null)
{
result = new BoundGlobalFunctionCall(nameExpr, BindArguments(x.CallSignature.Parameters));
Expand All @@ -887,11 +893,17 @@ protected BoundExpression BindFunctionCall(AST.FunctionCall x, BoundExpression b

Debug.Assert(boundTarget == null);

var boundname = (staticMtdCall is AST.DirectStMtdCall dm)
var boundStaticTarget = BindTypeRef(staticMtdCall.TargetType, objectTypeInfoSemantic: true);
var boundName = (staticMtdCall is AST.DirectStMtdCall dm)
? new BoundRoutineName(new QualifiedName(dm.MethodName))
: new BoundRoutineName(new BoundConversionEx(BindExpression(((AST.IndirectStMtdCall)staticMtdCall).MethodNameExpression), BoundTypeRefFactory.StringTypeRef));

result = new BoundStaticFunctionCall(BindTypeRef(staticMtdCall.TargetType, objectTypeInfoSemantic: true), boundname, BindArguments(x.CallSignature.Parameters));
if (x.CallSignature.IsCallableConvert) // callable convert syntax (...)
{
return new BoundCallableConvert(boundStaticTarget, boundName, DeclaringCompilation);
}

result = new BoundStaticFunctionCall(boundStaticTarget, boundName, BindArguments(x.CallSignature.Parameters));
}
else
{
Expand Down

0 comments on commit 59abe71

Please sign in to comment.