// Argument coercion and validation helpers for procedure resolution: each // reads one positional CALL argument (or a list form) as a typed value, // returning a plan error naming the procedure, argument, and position on a // mismatch. Split from call.go, which holds the CALL stage building and // procedure resolution.
package plan import ( ) func expectArgCount( string, []value.Value, int, string) error { if len() != { return planErrf("%s(%s) expects %d arguments, got %d", , , , len()) } return nil } func maxArgs( string, []value.Value, int, string) error { if len() > { return planErrf("%s(%s) takes at most %d arguments, got %d", , , , len()) } return nil } func strArg( string, []value.Value, int, string) (string, error) { if < len() { if , := [].AsStr(); { return , nil } } return "", planErrf("%s argument `%s` (position %d) must be a string", , , ) } func f64Arg( string, []value.Value, int, string) (float64, error) { if < len() { if , := numArg([]); { return , nil } } return 0, planErrf("%s argument `%s` (position %d) must be a number", , , ) } // numArg widens an int or float value to float64. func numArg( value.Value) (float64, bool) { if , := .AsFloat(); { return , true } if , := .AsInt(); { return float64(), true } return 0, false } func f64ArgOr( string, []value.Value, int, string, float64) (float64, error) { if >= len() || [].IsNull() { return , nil } return f64Arg(, , , ) } func boolArgOr( string, []value.Value, int, string, bool) (bool, error) { if >= len() || [].IsNull() { return , nil } if , := [].AsBool(); { return , nil } return false, planErrf("%s argument `%s` (position %d) must be a boolean", , , ) } func u32ArgOr( string, []value.Value, int, string, uint32) (uint32, error) { if >= len() || [].IsNull() { return , nil } if , := [].AsInt(); && >= 0 { return uint32(), nil } return 0, planErrf("%s argument `%s` (position %d) must be a non-negative integer", , , ) } func i64Arg( string, []value.Value, int, string) (int64, error) { if < len() { if , := [].AsInt(); { return , nil } } return 0, planErrf("%s argument `%s` (position %d) must be an integer", , , ) } // nodeArg accepts a bound node or a non-negative integer node id. func nodeArg( string, []value.Value, int, string) (graph.NodeID, error) { if < len() { if , := [].AsNode(); { return , nil } if , := [].AsInt(); && >= 0 { return graph.NodeID(), nil } } return 0, planErrf("%s argument `%s` (position %d) must be a node or a non-negative integer node id", , , ) } // nodesArg accepts a list of nodes/ids or a single node/id. func nodesArg( string, []value.Value, int, string) ([]graph.NodeID, error) { := func() ([]graph.NodeID, error) { return nil, planErrf("%s argument `%s` (position %d) must be a node/id or a list of them", , , ) } if >= len() { return () } if , := [].AsList(); { := make([]graph.NodeID, len()) for , := range { if , := .AsNode(); { [] = } else if , := .AsInt(); && >= 0 { [] = graph.NodeID() } else { return () } } return , nil } , := nodeArg(, , , ) if != nil { return () } return []graph.NodeID{}, nil } // f64sArg accepts a list of numbers or a single number. func f64sArg( string, []value.Value, int, string) ([]float64, error) { := func() ([]float64, error) { return nil, planErrf("%s argument `%s` (position %d) must be a number or a list of numbers", , , ) } if >= len() { return () } if , := [].AsList(); { := make([]float64, len()) for , := range { , := numArg() if ! { return () } [] = } return , nil } if , := numArg([]); { return []float64{}, nil } return () } // strsArg accepts a list of strings or a single string. func strsArg( string, []value.Value, int, string) ([]string, error) { := func() ([]string, error) { return nil, planErrf("%s argument `%s` (position %d) must be a string or a list of strings", , , ) } if >= len() { return () } if , := [].AsList(); { := make([]string, len()) for , := range { , := .AsStr() if ! { return () } [] = } return , nil } if , := [].AsStr(); { return []string{}, nil } return () } // dirArg parses a direction argument ('both'/'outgoing'/'out'/ // 'incoming'/'in'). func dirArg( string, []value.Value, int) (graph.Direction, error) { , := strArg(, , , "direction") if != nil { return graph.Both, planErrf("%s direction argument must be a string", ) } switch lower() { case "both": return graph.Both, nil case "outgoing", "out": return graph.Outgoing, nil case "incoming", "in": return graph.Incoming, nil } return graph.Both, planErrf("%s direction must be 'both'/'outgoing'/'incoming', got `%s`", , ) }