1
- use expression:: Context ;
2
- use expression:: DataSource ;
3
- use expression:: Object ;
4
- use std:: fmt:: Debug ;
5
- use std:: io:: BufRead ;
6
- use std:: io:: BufReader ;
7
- use std:: io:: BufWriter ;
8
- use std:: io:: Write ;
9
-
10
1
/// A simple REPL to demonstrate the use of the expression crate.
11
2
/// # Features:
12
- /// - Basic expression evaluation
13
- /// - Simple table for demonstrating addresses
14
- /// - Demonstrate complex usage of the API
3
+ /// - Basic expression evaluation: [`repl.rs:169`](./#L169)
4
+ /// - Simple table for demonstrating addresses: [`repl.rs:30`](./#L30)
5
+ /// - A top-level `eval` function to demonstrate programmatic evaluation: [`repl.rs:137`](./#L137)
6
+ /// - A `<<` operator to demonstrate operator registration: [`repl.rs:144`](./#L144)
15
7
///
16
8
/// Type an expression into the REPL and press enter.
17
9
/// The following commands are available:
@@ -23,6 +15,16 @@ use std::io::Write;
23
15
/// # Addresses:
24
16
/// Addresses are of the form `column:row` where `column` is the name of the column and `row` is the row number. Therefore, columns may contain `:`.
25
17
18
+ use std:: any:: Any ;
19
+ use expression:: Context ;
20
+ use expression:: OperatorBuilder ;
21
+ use expression:: DataSource ;
22
+ use expression:: Object ;
23
+ use std:: fmt:: Debug ;
24
+ use std:: io:: BufRead ;
25
+ use std:: io:: BufReader ;
26
+ use std:: io:: Write ;
27
+
26
28
#[ derive( Debug , Clone ) ]
27
29
struct Table {
28
30
columns : Vec < String > ,
@@ -31,6 +33,10 @@ struct Table {
31
33
32
34
impl DataSource for Table {
33
35
fn query ( & self , query : impl AsRef < str > ) -> Option < Object > {
36
+
37
+ // Parse the address into a usable format.
38
+ // Since the address is of the form `column:row`, we can split the address at the last `:`.
39
+
34
40
let ( column, row) = query. as_ref ( ) . split_at ( query. as_ref ( ) . rfind ( ':' ) ?) ;
35
41
let col = self . columns . iter ( ) . position ( |c| c == column) ?;
36
42
@@ -126,12 +132,34 @@ mod commands {
126
132
}
127
133
128
134
pub fn main ( ) {
129
- let mut cx = Context :: new ( Table :: empty ( [ "a" , "b" , "c" ] ) ) ;
135
+ let mut cx = Context :: new ( Table :: empty ( [ "a" , "b" , "c" ] ) )
136
+ . with_fn ( "eval" , |cx, args| {
137
+ if let Some ( Object :: String ( s) ) = args. get ( 0 ) {
138
+ cx. evaluate ( s)
139
+ } else {
140
+ Ok ( Object :: Nothing )
141
+ }
142
+ } )
143
+ . with_operator ( OperatorBuilder :: new ( )
144
+ . operands ( 2 )
145
+ . symbol ( "<<" )
146
+ . handler ( |args| {
147
+ let ( Some ( Object :: Number ( base) ) , Some ( Object :: Number ( shift) ) ) = ( args. get ( 0 ) , args. get ( 1 ) ) else {
148
+ return Err ( expression:: Error :: other ( "<< requires two numbers" ) )
149
+ } ;
150
+
151
+ let base = * base as i64 ;
152
+ let shift = * shift as i64 ;
153
+
154
+ Ok ( Object :: Number ( ( base << shift) as f64 ) )
155
+ } )
156
+ . build ( ) ) ;
130
157
131
158
loop {
132
159
let cmd = prompt ( "> " ) ;
133
160
134
161
match cmd. trim ( ) {
162
+ "" => continue ,
135
163
"/exit" => break ,
136
164
"/dump" => println ! ( "{:#?}" , cx. provider( ) ) ,
137
165
cmd if cmd. starts_with ( "/set " ) => commands:: set ( & mut cx, cmd[ 5 ..] . trim ( ) ) ,
0 commit comments