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 ;
1
8
use std:: io:: Write ;
2
- use expression:: {
3
- Context ,
4
- DataSource ,
5
- eval:: Object
6
- } ;
7
-
8
- struct RowInner {
9
- col1 : String ,
10
- col2 : f64
11
- }
12
9
13
- struct ExampleProvider {
14
- values : Vec < String >
10
+ /// A simple REPL to demonstrate the use of the expression crate.
11
+ /// # Features:
12
+ /// - Basic expression evaluation
13
+ /// - Simple table for demonstrating addresses
14
+ /// - Demonstrate complex usage of the API
15
+ ///
16
+ /// Type an expression into the REPL and press enter.
17
+ /// The following commands are available:
18
+ /// - /exit: Exit the REPL
19
+ /// - /dump: Dump the table
20
+ /// - /set <addr>: Set the value of an address
21
+ /// - /func <name> <arg1> <arg2> ...: Define a function
22
+ ///
23
+ /// # Addresses:
24
+ /// 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
+
26
+ #[ derive( Debug , Clone ) ]
27
+ struct Table {
28
+ columns : Vec < String > ,
29
+ data : Vec < Object > ,
15
30
}
16
31
17
- impl DataSource for ExampleProvider {
32
+ impl DataSource for Table {
18
33
fn query ( & self , query : impl AsRef < str > ) -> Option < Object > {
19
- let index = query. as_ref ( ) . parse :: < usize > ( ) . ok ( ) ?;
34
+ let ( column, row) = query. as_ref ( ) . split_at ( query. as_ref ( ) . rfind ( ':' ) ?) ;
35
+ let col = self . columns . iter ( ) . position ( |c| c == column) ?;
36
+
37
+ self . data
38
+ . get ( ( & row[ 1 ..] ) . parse :: < usize > ( ) . ok ( ) ? * self . columns . len ( ) + col)
39
+ . map ( |i| i. clone ( ) )
40
+ }
41
+ }
42
+
43
+ impl Table {
44
+ pub fn empty < Col : AsRef < str > > ( cols : impl AsRef < [ Col ] > ) -> Self {
45
+ Self {
46
+ columns : cols. as_ref ( ) . iter ( ) . map ( |c| c. as_ref ( ) . to_string ( ) ) . collect ( ) ,
47
+ data : vec ! [ ] ,
48
+ }
49
+ }
50
+
51
+ pub fn set ( & mut self , addr : impl AsRef < str > , value : Object ) -> Option < Object > {
52
+ let ( column, row) = addr. as_ref ( ) . split_at ( addr. as_ref ( ) . rfind ( ':' ) ?) ;
53
+ let col = self . columns . iter ( ) . position ( |c| c == column) ?;
54
+
55
+ let index = ( & row[ 1 ..] ) . parse :: < usize > ( ) . ok ( ) ? * self . columns . len ( ) + col;
56
+ if index >= self . data . len ( ) {
57
+ self . data . resize ( index + 1 , Object :: Nothing ) ;
58
+ }
20
59
21
- self . values . get ( index)
22
- . map ( |i| Object :: String ( i. clone ( ) ) )
60
+ self . data [ index] = value. clone ( ) ;
61
+
62
+ Some ( value)
23
63
}
24
64
}
25
65
26
- pub fn main ( ) -> std:: io:: Result < ( ) > {
27
- let cx = Context :: new ( ExampleProvider {
28
- values : vec ! [ ]
29
- } ) ;
66
+ fn prompt ( prompt : impl AsRef < str > ) -> String {
67
+ let mut stdin = BufReader :: new ( std:: io:: stdin ( ) ) ;
68
+
69
+ std:: io:: stderr ( ) . write_all ( prompt. as_ref ( ) . as_bytes ( ) ) . unwrap ( ) ;
70
+ std:: io:: stderr ( ) . flush ( ) . unwrap ( ) ;
30
71
31
- let mut buffer = String :: new ( ) ;
72
+ let mut cmd = String :: new ( ) ;
73
+ stdin. read_line ( & mut cmd) . unwrap ( ) ;
32
74
33
- eprint ! ( "> " ) ;
34
- std :: io :: stderr ( ) . flush ( ) ? ;
75
+ cmd . trim ( ) . to_string ( )
76
+ }
35
77
36
- while let Ok ( len) = std:: io:: stdin ( ) . read_line ( & mut buffer) {
37
- let program = buffer[ 0 ..len] . trim ( ) ;
78
+ mod commands {
79
+ use crate :: prompt;
80
+ use crate :: Table ;
81
+ use expression:: Context ;
82
+ use expression:: Object ;
38
83
39
- match cx. evaluate ( program) {
40
- Ok ( result) => println ! ( "{:#?}" , result) ,
41
- Err ( err) => println ! ( "Error: {:?}" , err)
84
+ pub fn set ( cx : & mut Context < Table > , addr : impl AsRef < str > ) {
85
+ let addr = addr. as_ref ( ) ;
86
+
87
+ match cx. evaluate ( prompt ( "--> " ) ) {
88
+ Ok ( v) => {
89
+ match cx. provider_mut ( ) . set ( addr, v. clone ( ) ) {
90
+ Some ( v) => eprintln ! ( "Set {{{addr}}} to {v}" ) ,
91
+ None => eprintln ! ( "Unable to set {{{addr}}}" ) ,
92
+ } ;
93
+ }
94
+ Err ( err) => eprintln ! ( "{}" , err) ,
42
95
}
96
+ }
97
+ pub fn func ( cx : & mut Context < Table > , func : impl AsRef < str > ) {
98
+ let bindings = func
99
+ . as_ref ( )
100
+ . split_whitespace ( )
101
+ . map ( str:: trim)
102
+ . map ( ToOwned :: to_owned)
103
+ . collect :: < Vec < _ > > ( ) ;
104
+
105
+ let ( name, bindings) = bindings. split_first ( ) . unwrap ( ) ;
106
+ let bindings = bindings. to_vec ( ) ; // Create owned copy of bindings
107
+
108
+ let body = prompt ( "--> " ) ;
43
109
44
- eprint ! ( "> " ) ;
45
- std:: io:: stderr ( ) . flush ( ) ?;
46
- buffer. clear ( ) ;
110
+ cx. push_fn ( name, move |mut cx, args| {
111
+ for ( a, arg) in bindings. iter ( ) . enumerate ( ) {
112
+ cx. push_global ( arg, args. get ( a) . cloned ( ) . unwrap_or ( Object :: Nothing ) ) ;
113
+ }
114
+
115
+ cx. evaluate ( & body)
116
+ } ) ;
47
117
}
118
+ pub fn global ( cx : & mut Context < Table > , name : impl AsRef < str > ) {
119
+ let name = name. as_ref ( ) ;
48
120
49
- Ok ( ( ) )
50
- }
121
+ match cx. evaluate ( prompt ( "--> " ) ) {
122
+ Ok ( v) => cx. push_global ( name, v) ,
123
+ Err ( err) => eprintln ! ( "{}" , err)
124
+ } ;
125
+ }
126
+ }
127
+
128
+ pub fn main ( ) {
129
+ let mut cx = Context :: new ( Table :: empty ( [ "a" , "b" , "c" ] ) ) ;
130
+
131
+ loop {
132
+ let cmd = prompt ( "> " ) ;
133
+
134
+ match cmd. trim ( ) {
135
+ "/exit" => break ,
136
+ "/dump" => println ! ( "{:#?}" , cx. provider( ) ) ,
137
+ cmd if cmd. starts_with ( "/set " ) => commands:: set ( & mut cx, cmd[ 5 ..] . trim ( ) ) ,
138
+ cmd if cmd. starts_with ( "/func " ) => commands:: func ( & mut cx, cmd[ 6 ..] . trim ( ) ) ,
139
+ cmd if cmd. starts_with ( "/glob " ) => commands:: global ( & mut cx, cmd[ 6 ..] . trim ( ) ) ,
140
+ cmd => match cx. evaluate ( cmd) {
141
+ Ok ( v) => println ! ( "{}" , v) ,
142
+ Err ( err) => eprintln ! ( "{}" , err) ,
143
+ } ,
144
+ }
145
+ }
146
+ }
0 commit comments