Skip to content

Instantly share code, notes, and snippets.

@moiseev
Created February 3, 2010 13:31
Show Gist options
  • Save moiseev/293600 to your computer and use it in GitHub Desktop.
Save moiseev/293600 to your computer and use it in GitHub Desktop.
type LogOp =
| Or
| And
type Cond =
| Eq
| Neq
| Greater
| Less
| GreaterOrEqual
| LessOrEqual
| Contains
| StartsWith
| EndsWith
| In
type Item =
| Prop of string array
type Val =
| Number of int
| Str of string
| Numbers of int array
| Strs of string array
type Clause =
| Simple of Item * Cond * Val
| Complex of Clause * LogOp * Clause
namespace Wepr
open System
open System.Linq
open System.Linq.Expressions
open System.Collections.Generic
module Extensions =
// F# extension methods
type System.Linq.IQueryable<'TSource> with
member this.Where (s:String) =
let expr = Wepr.GetExpression<'TSource> s :?> Expression<Func<'TSource, bool>>
Queryable.Where(this, expr)
type System.Collections.Generic.IEnumerable<'TSource> with
member this.Where (s:String) =
let dlg = Wepr.Compile<'TSource> s
let predicate (arg: 'TSource) = dlg.DynamicInvoke arg :?> bool
Enumerable.Where(this, predicate)
[<System.Runtime.CompilerServices.Extension>]
module QueryableExtensions =
open Extensions
// C#-visible extension methods
[<System.Runtime.CompilerServices.Extension>]
let Where (src:IQueryable<'a>, where:String) = src.Where(where)
[<System.Runtime.CompilerServices.Extension>]
module EnumerableExtensions =
open Extensions
[<System.Runtime.CompilerServices.Extension>]
let Where (src:IEnumerable<'a>, where:String) = src.Where(where)
{
module Wepr.Lexer
open System
open System.Text
open Wepr
open Wepr.Parser
let toString bs = Encoding.ASCII.GetString(bs)
let unquote (s:String) = s.[1..(s.Length-2)]
let splitString (sep:String) (s:String) = s.Split([|sep|], StringSplitOptions.RemoveEmptyEntries)
let trimString (s:String) = s.Trim()
}
let whitespace = ['\t' ' ']
let quotes = ['\'']
let literal = ['a'-'z' 'A'-'Z']+
let prop = ['a'-'z' 'A'-'Z' '.']+
let number = ['0'-'9']+
let quoted = ('\'' [^'\'']* '\'')
let in_strings = (quoted (',' [' ']+ quoted)*)+
let in_numbers = (number (',' [' ']+ number)*)+
rule token = parse
whitespace { token lexbuf }
| "AND" | "and" { AND }
| "OR" | "or" { OR }
| '(' { LPAREN }
| ')' { RPAREN }
| "=" { EQ }
| "!=" { NEQ }
| "<>" { NEQ }
| ">" { GREATER }
| "<" { LESS }
| ">=" { GREATEROREQ }
| "<=" { LESSOREQ }
| "Contains" { CONTAINS }
| "StartsWith" { STARTSWITH }
| "EndsWith" { ENDSWITH }
| number { INT (toString lexbuf.Lexeme |> Int32.Parse) }
| quoted { QUOTED (toString lexbuf.Lexeme |> unquote) }
| ("IN" | "in") { IN }
| in_strings {
STRINGS (toString lexbuf.Lexeme |> splitString "," |> Array.map (trimString >> unquote) )}
| in_numbers {
NUMBERS (toString lexbuf.Lexeme |> splitString "," |> Array.map (trimString >> Int32.Parse) )}
| prop { PROP (toString lexbuf.Lexeme |> splitString ".") }
| eof { EOF }
%{
open Wepr
%}
%start Start
%token <string> STRING
%token <string> QUOTED
%token <string array> PROP
%token <string array> STRINGS
%token <int array> NUMBERS
%token <int> INT
%token LPAREN RPAREN DOT
%token AND OR
%token EQ NEQ LESS GREATER LESSOREQ GREATEROREQ CONTAINS STARTSWITH ENDSWITH IN
%token EOF
%type <Clause> Start
%%
Start: Clause { $1 }
Clause:
LPAREN Clause RPAREN { $2 }
| Clause AND Clause { Complex ($1, And, $3) }
| Clause OR Clause { Complex ($1, Or, $3) }
| Field EQ Literal { Simple ($1, Eq, $3) }
| Field NEQ Literal { Simple ($1, Neq, $3) }
| Field LESS Literal { Simple ($1, Less, $3) }
| Field GREATER Literal { Simple ($1, Greater, $3) }
| Field LESSOREQ Literal { Simple ($1, LessOrEqual, $3) }
| Field GREATEROREQ Literal { Simple ($1, GreaterOrEqual, $3) }
| Field CONTAINS Literal { Simple ($1, Contains, $3) }
| Field STARTSWITH Literal { Simple ($1, StartsWith, $3) }
| Field ENDSWITH Literal { Simple ($1, EndsWith, $3) }
| Field IN LPAREN STRINGS RPAREN { Simple ($1, In, (Strs $4)) }
| Field IN LPAREN NUMBERS RPAREN { Simple ($1, In, (Numbers $4)) }
Field:
| PROP { Prop ($1) }
Literal:
QUOTED { Str $1 }
| INT { Number $1 }
| STRINGS { Strs $1 }
| NUMBERS { Numbers $1 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment