@@ -2,14 +2,43 @@ import * as lexical from '../parser/lexical'
2
2
import assert from '../util/assert'
3
3
import Scope from 'src/scope/scope'
4
4
import { range , last } from 'src/util/underscore'
5
+ import { isComparable } from 'src/drop/icomparable'
6
+ import { NullDrop } from 'src/drop/null-drop'
7
+ import { EmptyDrop } from 'src/drop/empty-drop'
8
+ import { BlankDrop } from 'src/drop/blank-drop'
9
+ import { isDrop } from 'src/drop/idrop'
5
10
6
- const operators = {
7
- '==' : ( l : any , r : any ) => l === r ,
8
- '!=' : ( l : any , r : any ) => l !== r ,
9
- '>' : ( l : any , r : any ) => l !== null && r !== null && l > r ,
10
- '<' : ( l : any , r : any ) => l !== null && r !== null && l < r ,
11
- '>=' : ( l : any , r : any ) => l !== null && r !== null && l >= r ,
12
- '<=' : ( l : any , r : any ) => l !== null && r !== null && l <= r ,
11
+ const binaryOperators : { [ key : string ] : ( lhs : any , rhs : any ) => boolean } = {
12
+ '==' : ( l : any , r : any ) => {
13
+ if ( isComparable ( l ) ) return l . equals ( r )
14
+ if ( isComparable ( r ) ) return r . equals ( l )
15
+ return l === r
16
+ } ,
17
+ '!=' : ( l : any , r : any ) => {
18
+ if ( isComparable ( l ) ) return ! l . equals ( r )
19
+ if ( isComparable ( r ) ) return ! r . equals ( l )
20
+ return l !== r
21
+ } ,
22
+ '>' : ( l : any , r : any ) => {
23
+ if ( isComparable ( l ) ) return l . gt ( r )
24
+ if ( isComparable ( r ) ) return r . lt ( l )
25
+ return l > r
26
+ } ,
27
+ '<' : ( l : any , r : any ) => {
28
+ if ( isComparable ( l ) ) return l . lt ( r )
29
+ if ( isComparable ( r ) ) return r . gt ( l )
30
+ return l < r
31
+ } ,
32
+ '>=' : ( l : any , r : any ) => {
33
+ if ( isComparable ( l ) ) return l . geq ( r )
34
+ if ( isComparable ( r ) ) return r . leq ( l )
35
+ return l >= r
36
+ } ,
37
+ '<=' : ( l : any , r : any ) => {
38
+ if ( isComparable ( l ) ) return l . leq ( r )
39
+ if ( isComparable ( r ) ) return r . geq ( l )
40
+ return l <= r
41
+ } ,
13
42
'contains' : ( l : any , r : any ) => {
14
43
if ( ! l ) return false
15
44
if ( typeof l . indexOf !== 'function' ) return false
@@ -19,41 +48,54 @@ const operators = {
19
48
'or' : ( l : any , r : any ) => isTruthy ( l ) || isTruthy ( r )
20
49
}
21
50
22
- export function evalExp ( exp : string , scope : Scope ) : any {
23
- assert ( scope , 'unable to evalExp : scope undefined' )
51
+ export function parseExp ( exp : string , scope : Scope ) : any {
52
+ assert ( scope , 'unable to parseExp : scope undefined' )
24
53
const operatorREs = lexical . operators
25
54
let match
26
55
for ( let i = 0 ; i < operatorREs . length ; i ++ ) {
27
56
const operatorRE = operatorREs [ i ]
28
57
const expRE = new RegExp ( `^(${ lexical . quoteBalanced . source } )(${ operatorRE . source } )(${ lexical . quoteBalanced . source } )$` )
29
58
if ( ( match = exp . match ( expRE ) ) ) {
30
- const l = evalExp ( match [ 1 ] , scope )
31
- const op = operators [ match [ 2 ] . trim ( ) ]
32
- const r = evalExp ( match [ 3 ] , scope )
59
+ const l = parseExp ( match [ 1 ] , scope )
60
+ const op = binaryOperators [ match [ 2 ] . trim ( ) ]
61
+ const r = parseExp ( match [ 3 ] , scope )
33
62
return op ( l , r )
34
63
}
35
64
}
36
65
37
66
if ( ( match = exp . match ( lexical . rangeLine ) ) ) {
38
- const low = evalValue ( match [ 1 ] , scope )
39
- const high = evalValue ( match [ 2 ] , scope )
67
+ const low = parseValue ( match [ 1 ] , scope )
68
+ const high = parseValue ( match [ 2 ] , scope )
40
69
return range ( low , high + 1 )
41
70
}
42
71
43
- return evalValue ( exp , scope )
72
+ return parseValue ( exp , scope )
73
+ }
74
+
75
+ export function evalExp ( str : string , scope : Scope ) : any {
76
+ const value = parseExp ( str , scope )
77
+ return isDrop ( value ) ? value . value ( ) : value
44
78
}
45
79
46
- export function evalValue ( str : string , scope : Scope ) {
80
+ function parseValue ( str : string , scope : Scope ) : any {
47
81
if ( ! str ) return null
48
82
str = str . trim ( )
49
83
50
84
if ( str === 'true' ) return true
51
85
if ( str === 'false' ) return false
86
+ if ( str === 'nil' || str === 'null' ) return new NullDrop ( )
87
+ if ( str === 'empty' ) return new EmptyDrop ( )
88
+ if ( str === 'blank' ) return new BlankDrop ( )
52
89
if ( ! isNaN ( Number ( str ) ) ) return Number ( str )
53
90
if ( ( str [ 0 ] === '"' || str [ 0 ] === "'" ) && str [ 0 ] === last ( str ) ) return str . slice ( 1 , - 1 )
54
91
return scope . get ( str )
55
92
}
56
93
94
+ export function evalValue ( str : string , scope : Scope ) : any {
95
+ const value = parseValue ( str , scope )
96
+ return isDrop ( value ) ? value . value ( ) : value
97
+ }
98
+
57
99
export function isTruthy ( val : any ) : boolean {
58
100
return ! isFalsy ( val )
59
101
}
0 commit comments