private ExpressionInfo AnalyzeNode(XmlNode node)
{
switch (node.LocalName)
{
case AstConstants.Nodes.Expr_ArrayDimFetch:
case AstConstants.Nodes.Expr_PropertyFetch: //Yes, array and property fetch can (currently) be handled alike.
return Node_Expr_ArrayDimFetch(node);
case AstConstants.Nodes.Expr_Variable:
return Node_Expr_Variable(node);
case AstConstants.Nodes.Expr_AssignRef:
// INVALID: Reference assignments _should_ be handled differently than normal assignments.
case AstConstants.Nodes.Expr_Assign:
return Node_Expr_Assign(node);
case AstConstants.Nodes.Expr_AssignOp_BitwiseAnd:
case AstConstants.Nodes.Expr_AssignOp_BitwiseOr:
case AstConstants.Nodes.Expr_AssignOp_BitwiseXor:
// POSSIBLY INCORRECT: See BinaryOp_Bitwise..
case AstConstants.Nodes.Expr_AssignOp_Div:
case AstConstants.Nodes.Expr_AssignOp_Minus:
case AstConstants.Nodes.Expr_AssignOp_Mod:
case AstConstants.Nodes.Expr_AssignOp_Plus:
case AstConstants.Nodes.Expr_AssignOp_Mul:
case AstConstants.Nodes.Expr_AssignOp_ShiftLeft:
case AstConstants.Nodes.Expr_AssignOp_ShiftRight:
case AstConstants.Nodes.Expr_AssignOp_Pow:
return Expr_AssignOp_NonSpecial_AlwaysSafe(node);
case AstConstants.Nodes.Expr_AssignOp_Concat:
return Expr_AssignOp_Concat(node);
case AstConstants.Nodes.Expr_Cast_Array:
case AstConstants.Nodes.Expr_Cast_Bool:
case AstConstants.Nodes.Expr_Cast_Double:
case AstConstants.Nodes.Expr_Cast_Int:
case AstConstants.Nodes.Expr_Cast_Object:
case AstConstants.Nodes.Expr_Cast_String:
case AstConstants.Nodes.Expr_Cast_Unset:
return Node_Expr_Cast(node);
case AstConstants.Nodes.Expr_ConstFetch:
// POSSIBLY INCORRECT: Not necessarily the right thing to do.
return new ExpressionInfo();
case AstConstants.Nodes.Scalar_LNumber:
case AstConstants.Nodes.Scalar_DNumber:
return Node_LDNumbers(node);
case AstConstants.Nodes.Expr_FuncCall:
return Node_FuncCall(node);
case AstConstants.Nodes.Stmt_Echo:
return Node_Echo(node);
case AstConstants.Nodes.Expr_New:
return Node_New(node);
case AstConstants.Nodes.Stmt_InlineHTML:
return new ExpressionInfo();
case AstConstants.Nodes.Expr_Ternary:
return Expr_Ternary(node);
case AstConstants.Nodes.Stmt_Case:
case AstConstants.Nodes.Stmt_Do:
case AstConstants.Nodes.Stmt_ElseIf:
case AstConstants.Nodes.Stmt_For:
case AstConstants.Nodes.Stmt_If:
case AstConstants.Nodes.Stmt_Switch:
case AstConstants.Nodes.Stmt_While:
return Analyze(Conditional.GetCondNode(node));
case AstConstants.Nodes.Expr_BinaryOp_BooleanAnd:
case AstConstants.Nodes.Expr_BinaryOp_BooleanOr:
return Expr_BinaryOp_BooleanOperator(node);
case AstConstants.Nodes.Expr_BinaryOp_ShiftLeft:
case AstConstants.Nodes.Expr_BinaryOp_ShiftRight:
// Docs: "Both operands and the result for the << and >> operators are always treated as integers." - https://php.net/manual/en/language.operators.bitwise.php
case AstConstants.Nodes.Expr_BinaryOp_Mod:
case AstConstants.Nodes.Expr_BinaryOp_Div:
// Docs: "Operands of modulus are converted to integers.." & "The division operator ("/") returns a float value unless the two operands are integers.." - https://php.net/language.operators.arithmetic
case AstConstants.Nodes.Expr_BinaryOp_BitwiseAnd:
case AstConstants.Nodes.Expr_BinaryOp_BitwiseOr:
case AstConstants.Nodes.Expr_BinaryOp_BitwiseXor:
// POSSIBLY INCORRECT: Docs: "If both operands for the &, | and ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string. In all other cases, both operands will be converted to integers.." - https://php.net/manual/en/language.operators.bitwise.php
case AstConstants.Nodes.Expr_BinaryOp_Minus:
case AstConstants.Nodes.Expr_BinaryOp_Mul:
case AstConstants.Nodes.Expr_BinaryOp_Plus:
case AstConstants.Nodes.Expr_BinaryOp_Pow:
case AstConstants.Nodes.Expr_BinaryOp_Equal:
case AstConstants.Nodes.Expr_BinaryOp_Greater:
case AstConstants.Nodes.Expr_BinaryOp_GreaterOrEqual:
case AstConstants.Nodes.Expr_BinaryOp_Identical:
case AstConstants.Nodes.Expr_BinaryOp_LogicalAnd:
case AstConstants.Nodes.Expr_BinaryOp_LogicalOr:
case AstConstants.Nodes.Expr_BinaryOp_LogicalXor:
case AstConstants.Nodes.Expr_BinaryOp_NotEqual:
case AstConstants.Nodes.Expr_BinaryOp_NotIdentical:
case AstConstants.Nodes.Expr_BinaryOp_Smaller:
case AstConstants.Nodes.Expr_BinaryOp_SmallerOrEqual:
return Expr_BinaryOp_NonSpecial_AlwaysSafe(node);
case AstConstants.Nodes.Scalar_MagicConst_Class:
case AstConstants.Nodes.Scalar_MagicConst_Dir:
case AstConstants.Nodes.Scalar_MagicConst_File:
case AstConstants.Nodes.Scalar_MagicConst_Function:
case AstConstants.Nodes.Scalar_MagicConst_Line:
case AstConstants.Nodes.Scalar_MagicConst_Method:
case AstConstants.Nodes.Scalar_MagicConst_Namespace:
case AstConstants.Nodes.Scalar_MagicConst_Trait:
return new ExpressionInfo(); // These are known values and should probably be resolved.
case AstConstants.Nodes.Expr_Isset:
return new ExpressionInfo();
case AstConstants.Nodes.Expr_BooleanNot:
return Expr_BooleanNot(node);
case AstConstants.Nodes.Scalar_String:
return new ExpressionInfo { ValueInfo = { Value = ScalarNode.GetStringValue(node), Type = "string"} };
case AstConstants.Nodes.Scalar_Encapsed:
return Scalar_Encapsed(node);
case AstConstants.Nodes.Expr_Print:
case AstConstants.Nodes.Expr_Exit:
return Expr_Exit(node);
case AstConstants.Nodes.Expr_BitwiseNot:
// POSSIBLY INCORRECT: Docs: "If the operand for the ~ operator is a string, the operation will be performed on the ASCII values.."
case AstConstants.Nodes.Expr_UnaryMinus:
case AstConstants.Nodes.Expr_UnaryPlus:
return Expr_UnaryOp_AlwaysSafe(node);
case AstConstants.Nodes.Expr_BinaryOp_Concat:
return Expr_BinaryOp_Concat(node);
case AstConstants.Nodes.Expr_PostDec:
case AstConstants.Nodes.Expr_PostInc:
case AstConstants.Nodes.Expr_PreInc:
case AstConstants.Nodes.Expr_PreDec:
return Expr_IncDec(node);
case AstConstants.Nodes.Expr_Array:
return Expr_Array(node);
case AstConstants.Nodes.Expr_Include:
return Expr_Include(node);
case AstConstants.Nodes.Stmt_Return:
return Stmt_Return(node);
case AstConstants.Nodes.Stmt_Foreach:
return Stmt_Foreach(node);
case AstConstants.Nodes.Expr_MethodCall:
return Node_MethodCall(node);
case AstConstants.Nodes.Stmt_Global:
return Stmt_Global(node);
case AstConstants.Nodes.Expr_ArrayItem:
case AstConstants.Nodes.Stmt_Break:
case AstConstants.Nodes.Stmt_Catch:
case AstConstants.Nodes.Stmt_ClassConst:
case AstConstants.Nodes.Stmt_ClassLike:
case AstConstants.Nodes.Stmt_Class:
case AstConstants.Nodes.Stmt_ClassMethod:
case AstConstants.Nodes.Stmt_Const:
case AstConstants.Nodes.Stmt_Continue:
case AstConstants.Nodes.Stmt_Declare:
case AstConstants.Nodes.Stmt_DeclareDeclare:
case AstConstants.Nodes.Stmt_Else:
case AstConstants.Nodes.Stmt_Function:
case AstConstants.Nodes.Stmt_Goto:
case AstConstants.Nodes.Stmt_HaltCompiler:
case AstConstants.Nodes.Stmt_Interface:
case AstConstants.Nodes.Stmt_Label:
case AstConstants.Nodes.Stmt_Namespace:
case AstConstants.Nodes.Stmt_Property:
case AstConstants.Nodes.Stmt_PropertyProperty:
case AstConstants.Nodes.Stmt_StaticVar:
case AstConstants.Nodes.Stmt_Static:
case AstConstants.Nodes.Stmt_Throw:
case AstConstants.Nodes.Stmt_Trait:
case AstConstants.Nodes.Stmt_TraitUse:
case AstConstants.Nodes.Stmt_TraitUseAdaption:
case AstConstants.Nodes.Stmt_Unset:
case AstConstants.Nodes.Stmt_Use:
case AstConstants.Nodes.Stmt_UseUse:
case AstConstants.Nodes.Expr_ClassConstFetch:
case AstConstants.Nodes.Expr_Closure:
case AstConstants.Nodes.Expr_ClosureUse:
case AstConstants.Nodes.Expr_Empty:
case AstConstants.Nodes.Expr_ErrorSuppress:
case AstConstants.Nodes.Expr_Eval:
case AstConstants.Nodes.Expr_Instanceof:
case AstConstants.Nodes.Expr_List:
case AstConstants.Nodes.Expr_ShellExec:
case AstConstants.Nodes.Expr_StaticCall:
case AstConstants.Nodes.Expr_StaticPropertyFetch:
case AstConstants.Nodes.Expr_Yield:
case AstConstants.Nodes.Arg:
case AstConstants.Nodes.Param:
case AstConstants.Nodes.Const:
case AstConstants.Nodes.Name:
return new ExpressionInfo();
default:
return new ExpressionInfo();
throw new NotImplementedException("Unknown AST node. Was " + node.Name);
}
}