package bql import ( "fmt" "pkg.jfrech.com/brief/bql/pl" ) func Parse(args []string) (BQL, error) { // convenience if len(args) > 0 && !pl.IsOpenParen(args[0]) { args = append([]string{"("}, append(args, ")")...) } asts, err := pl.Parse(args) if err != nil { return BQLEmpty{}, err } if len(asts) == 0 { return BQLEmpty{}, fmt.Errorf("no query") } else if len(asts) != 1 { panic("unreachable") } var ast pl.PL if len(asts) == 1 { ast = asts[0] } else { ast = pl.PLGrp{asts} } return parse(ast) } func parse(ast pl.PL) (BQL, error) { switch node := ast.(type) { default: return BQLEmpty{}, fmt.Errorf("unrecognized: %T", node) case pl.PLRaw: return BQLQry{node.Raw}, nil case pl.PLGrp: if len(node.Inner) <= 0 { return BQLEmpty{}, fmt.Errorf("invalid group: empty") } // convenience if len(node.Inner) > 0 { if head, ok := node.Inner[0].(pl.PLRaw); !(ok && (head.Raw == "not" || head.Raw == "and" || head.Raw == "or")) { node.Inner = append([]pl.PL{pl.PLRaw{"and"}}, node.Inner...) } } plraw, ok := node.Inner[0].(pl.PLRaw) if !ok { return BQLEmpty{}, fmt.Errorf("invalid group: improper head") } var qs []BQL for _, nodeinner := range node.Inner[1:] { q, err := parse(nodeinner) if err != nil { return BQLEmpty{}, err } qs = append(qs, q) } switch plraw.Raw { case "not": return BQLNot{qs}, nil case "and": return BQLAnd{qs}, nil case "or": return BQLOr{qs}, nil default: return BQLEmpty{}, fmt.Errorf("invalid group: unrecognised head: %q", plraw.Raw) } } }