1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Query::Parser
6
7Parser for queries, using the Foswiki::Infix::Parser.
8
9The default node type in the generated parse tree is Foswiki::Query::Node,
10though you can pass your own alternative class as an option (it must implement
11Foswiki::Infix::Node)
12
13=cut
14
15package Foswiki::Query::Parser;
16
17use strict;
18use warnings;
19use Assert;
20
21BEGIN {
22    if ( $Foswiki::cfg{UseLocale} ) {
23        require locale;
24        import locale();
25    }
26}
27
28use Foswiki::Infix::Parser ();
29our @ISA = ('Foswiki::Infix::Parser');
30
31use Foswiki::Query::Node ();
32
33#             operator name           precedence
34use Foswiki::Query::OP_or ();    #  100
35
36use Foswiki::Query::OP_and ();   #  200
37
38use Foswiki::Query::OP_not ();   #  300
39
40use Foswiki::Query::OP_comma (); #  400
41
42use Foswiki::Query::OP_lte   (); #  500
43use Foswiki::Query::OP_gt    (); #  500
44use Foswiki::Query::OP_gte   (); #  500
45use Foswiki::Query::OP_lt    (); #  500
46use Foswiki::Query::OP_match (); #  500
47use Foswiki::Query::OP_eq    (); #  500
48use Foswiki::Query::OP_like  (); #  500
49use Foswiki::Query::OP_ne    (); #  500
50use Foswiki::Query::OP_in    (); #  500
51
52use Foswiki::Query::OP_plus  (); #  600
53use Foswiki::Query::OP_minus (); #  600
54
55use Foswiki::Query::OP_times (); #  700
56use Foswiki::Query::OP_div   (); #  700
57
58use Foswiki::Query::OP_ref ();   #  800
59use Foswiki::Query::OP_dot ();   #  800
60
61use Foswiki::Query::OP_where (); #  900
62
63use Foswiki::Query::OP_lc     ();    # 1000
64use Foswiki::Query::OP_uc     ();    # 1000
65use Foswiki::Query::OP_d2n    ();    # 1000
66use Foswiki::Query::OP_length ();    # 1000
67use Foswiki::Query::OP_neg    ();    # 1000
68use Foswiki::Query::OP_int    ();    # 1000
69
70use Foswiki::Query::OP_ob ();        # 1100
71
72=begin TML
73Query Language BNF
74<verbatim>
75expr ::= and_expr 'or' expr | and_expr;
76and_expr ::= not_expr 'and' and_expr | not_expr;
77not_expr ::= 'not' comma_expr | comma_expr;
78comma_expr ::= cmp_expr ',' comma_expr | cmp_expr;
79cmp_expr ::= add_expr cmp_op cm_expr | add_expr;
80cmp_op ::= '<=' | '>=' | '<' | '>' | '=' | '=~' | '~' | '!=' | 'in';
81add_expr ::= mul_expr add_op add_expr | mul_expr;
82mul_expr ::= ref_expr mul_op mul_expr | ref_expr;
83mul_op ::= '*' | 'div';
84ref_expr ::= u_expr ref_op ref_expr | u_expr;
85ref_op ::= '/' | '.';
86u_expr ::= value uop u_expr | value;
87uop ::= 'lc' | 'uc' | 'd2n' | 'length' | '-' | 'int' | '@';
88value ::= <name> | <string> | <number>;
89</verbatim>
90String and Numbers are as defined in Foswiki::Infix::Parser. Names default
91to =/([A-Z:][A-Z0-9_:]*|({[A-Z][A-Z0-9_]*})+)/i=.
92
93See %SYSTEMWEB%.QuerySearch for details of the query language.
94
95=cut
96
97# Each operator is implemented by a class in Foswiki::Query. Note that
98# OP_empty is *not* included here; it is a pseudo-operator and does
99# not participate in parsing.
100use constant OPS => qw (match and eq lc lte not ref d2n gte length lt ob
101  uc dot gt like ne or where comma plus minus
102  neg times div in int );
103
104sub new {
105    my ( $class, $options ) = @_;
106
107    $options->{words}     ||= qr/([A-Z:][A-Z0-9_:]*|(\{[A-Z][A-Z0-9_]*\})+)/i;
108    $options->{nodeClass} ||= 'Foswiki::Query::Node';
109    my $this = $class->SUPER::new($options);
110    foreach my $op ( OPS() ) {
111        my $on = 'Foswiki::Query::OP_' . $op;
112        $this->addOperator( $on->new() );
113    }
114    return $this;
115}
116
117# Ensure there is at least one operand on the opstack when closing
118# a subexpression.
119sub onCloseExpr {
120    my ( $this, $opands ) = @_;
121    if ( !scalar(@$opands) ) {
122        require Foswiki::Query::OP_empty;
123        push( @$opands, $this->{node_factory}->emptyExpression() );
124    }
125}
126
1271;
128__END__
129Author: Crawford Currie http://c-dot.co.uk
130
131Foswiki - The Free and Open Source Wiki, http://foswiki.org/
132
133Copyright (C) 2008-2011 Foswiki Contributors. Foswiki Contributors
134are listed in the AUTHORS file in the root of this distribution.
135NOTE: Please extend that file, not this notice.
136
137Additional copyrights apply to some or all of the code in this
138file as follows:
139
140Copyright (C) 2005-2007 TWiki Contributors. All Rights Reserved.
141TWiki Contributors are listed in the AUTHORS file in the root
142of this distribution.
143
144This program is free software; you can redistribute it and/or
145modify it under the terms of the GNU General Public License
146as published by the Free Software Foundation; either version 2
147of the License, or (at your option) any later version. For
148more details read LICENSE in the root of this distribution.
149
150This program is distributed in the hope that it will be useful,
151but WITHOUT ANY WARRANTY; without even the implied warranty of
152MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
153
154As per the GPL, removal of this notice is prohibited.
155