I have written a custom logger and wanted to add the name of POUs as the pszComponent
for easier debugging.
I wrote a custom FB_init
which accepts as input the name of the POU as a string and encountered puzzling behavior (to me at least).
Could someone explain to me why the following compiles
VAR
name : STRING := __POUNAME();
test : FB_logAdd(sCmpName:=name);
END_VAR
but the following
VAR
test : FB_logAdd(sCmpName:=__POUNAME());
END_VAR
throws the following compiler error?
[ERROR] Internal error:System.NullReferenceException: Object reference not set to an instance of an object. at _3S.CoDeSys.LanguageModelManager.CompileContext.NeedsExternalFunctionCall(IOperatorExpression op, ICompiledType type, String& stFunctionName, TypeClass& tcWithType) at _3S.CoDeSys.Compiler35160.ExpressionTypifier.(_IOperatorExpression ) at _3S.CoDeSys.LanguageModelManager.OperatorExpression.Accept(IExprementVisitor visitor) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , _ISignature , ISignature , ISignature , IScope5 , _ICompileContext , IList`1 , IVariable[] , ExpressionTypifier , TypeChecker , ErrorVisitor ) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(IList`1& , IVariable[] , _IVariable , IScope5 , _ICompileContext , _ISignature , ISignature , ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor ) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature , ISignature , ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor ) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor , ISignature , ISignature ) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature ) at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_ISignature , IScope5 , _ICompileContext ) at _3S.CoDeSys.Compiler35160.Compiler.(_ICompileContext , _IPreCompileContext , _IPreCompileContext , _ICompileContext , Boolean , Boolean , Boolean& , IProgressCallback ) at _3S.CoDeSys.Compiler35160.Compiler.(_ICompileContext , Boolean , Boolean , _IPreCompileContext , _IPreCompileContext , _ICompileContext , Boolean , Boolean& , IProgressCallback ) at _3S.CoDeSys.Compiler35160.Compiler.(Guid , Boolean , Boolean , Boolean , Boolean& , _ICompileContext& , _ICompileContext& , IProgressCallback , Boolean , Boolean , Boolean )
Is it because __POUNAME()
behaves like a function block instead of a function like I assumed?
Which is why
VAR
test : FB_logAdd(pCmpName:=ADR(__POUNAME()));
END_VAR
also works if I change the input to a string pointer?
Edit 1
My initial FB_init
looked like this
//FB_Init is always available implicitly and it is used primarily for initialization.
//The return value is not evaluated. For a specific influence, you can also declare the
//methods explicitly and provide additional code there with the standard initialization
//code. You can evaluate the return value.
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
bInCopyCode: BOOL; // TRUE: the instance will be copied to the copy code afterward (online change)
sCmpName : STRING;
END_VAR
THIS^.sCmpName := sCmpName;
Since I wanted to initialize the function block with FB_logAdd(sCmpName:=__POUNAME())
(which still throws the above error)
If I use FB_logAdd(sCmpName:=THIS^.___POUNAME())
, it throws the compiler error
C0004: '__POUNAME' is no component of 'THIS^'
which makes sense since __POUNAME()
is an operator and doesn't actually belong to the parent function block (I think)