@@ -25,8 +25,8 @@ use serde_json::{from_str, to_string, Map, Value};
2525use serde_norway:: { from_reader, from_str as from_yaml_str} ;
2626
2727use crate :: pdl:: ast:: {
28- PdlBlock , PdlCallBlock , PdlModelBlock , PdlParser , PdlPythonCodeBlock , PdlReadBlock ,
29- PdlRepeatBlock , PdlTextBlock , PdlUsage , Role ,
28+ PdlBlock , PdlCallBlock , PdlListOrString , PdlModelBlock , PdlParser , PdlPythonCodeBlock ,
29+ PdlReadBlock , PdlRepeatBlock , PdlTextBlock , PdlUsage , Role ,
3030} ;
3131
3232type Context = Vec < ChatMessage > ;
@@ -112,7 +112,7 @@ impl<'a> Interpreter<'a> {
112112 self . run_with_emit ( program, context, self . emit ) . await
113113 }
114114
115- // Evaluate as a Jinja2 expression
115+ // Evaluate String as a Jinja2 expression
116116 fn eval < T : serde:: de:: DeserializeOwned + :: std:: convert:: From < String > > (
117117 & self ,
118118 expr : & String ,
@@ -134,6 +134,43 @@ impl<'a> Interpreter<'a> {
134134 } ) )
135135 }
136136
137+ fn eval_complex ( & self , expr : & Value ) -> Result < Value , Box < dyn Error + Send + Sync > > {
138+ match expr {
139+ Value :: String ( s) => self . eval ( s) ,
140+ Value :: Array ( a) => Ok ( Value :: Array (
141+ a. iter ( )
142+ . map ( |v| self . eval_complex ( v) )
143+ . collect :: < Result < _ , _ > > ( ) ?,
144+ ) ) ,
145+ Value :: Object ( o) => Ok ( Value :: Object (
146+ o. iter ( )
147+ . map ( |( k, v) | match self . eval_complex ( v) {
148+ Ok ( v) => Ok ( ( k. clone ( ) , v) ) ,
149+ Err ( e) => Err ( e) ,
150+ } )
151+ . collect :: < Result < _ , _ > > ( ) ?,
152+ ) ) ,
153+ v => Ok ( v. clone ( ) ) ,
154+ }
155+ }
156+
157+ // Evaluate an string or list of Values into a list of Values
158+ fn eval_list_or_string (
159+ & self ,
160+ expr : & PdlListOrString ,
161+ ) -> Result < Vec < Value > , Box < dyn Error + Send + Sync > > {
162+ match expr {
163+ PdlListOrString :: String ( s) => match self . eval :: < Value > ( s) ? {
164+ Value :: Array ( a) => Ok ( a) ,
165+ x => Err ( Box :: from ( format ! (
166+ "Jinja string expanded to non-list. {} -> {:?}" ,
167+ s, x
168+ ) ) ) ,
169+ } ,
170+ PdlListOrString :: List ( l) => l. iter ( ) . map ( |v| self . eval_complex ( v) ) . collect ( ) ,
171+ }
172+ }
173+
137174 // Run a PdlBlock::String
138175 async fn run_string ( & self , msg : & String , _context : Context ) -> Interpretation {
139176 let trace = self . eval :: < PdlBlock > ( msg) ?;
@@ -179,53 +216,26 @@ impl<'a> Interpreter<'a> {
179216 eprintln ! ( "Call {:?}({:?})" , block. call, block. args) ;
180217 }
181218
182- let args = match & block. args {
183- Some ( x) => match x {
184- // args is a string; eval it and see if we get an Object out the other side
185- Value :: String ( s) => match self . eval :: < Value > ( & s) ? {
186- // args was a string that eval'd to an Object
187- Value :: Object ( m) => Ok ( Some ( self . to_pdl ( & m) ) ) ,
188- // args was a string that eval'd to something we don't understand
189- y => Err ( Box :: < dyn Error + Send + Sync > :: from ( format ! (
190- "Invalid arguments to call {:?}" ,
191- y
192- ) ) ) ,
193- } ,
194- // args is already an Object
195- Value :: Object ( m) => Ok ( Some ( self . to_pdl ( & m) ) ) ,
196- // args is something we don't understand
197- y => Err ( Box :: from ( format ! ( "Invalid arguments to call {:?}" , y) ) ) ,
198- } ,
199- // no args... that's ok (TODO: check against function schema)
200- None => Ok ( None ) ,
201- } ?;
202- self . extend_scope_with_map ( & args) ;
219+ if let Some ( args) = & block. args {
220+ match self . eval_complex ( args) ? {
221+ Value :: Object ( m) => Ok ( self . extend_scope_with_json_map ( m) ) ,
222+ x => Err ( Box :: < dyn Error + Send + Sync > :: from ( format ! (
223+ "Call arguments not a map: {:?}" ,
224+ x
225+ ) ) ) ,
226+ } ?;
227+ }
203228
204229 let res = match self . eval :: < PdlBlock > ( & block. call ) ? {
205230 PdlBlock :: Function ( f) => self . run ( & f. return_ , context. clone ( ) ) . await ,
206231 _ => Err ( Box :: from ( format ! ( "call of non-function {:?}" , & block. call) ) ) ,
207232 } ;
208- self . scope . pop ( ) ;
209233
210- res
211- }
234+ if let Some ( _) = block. args {
235+ self . scope . pop ( ) ;
236+ }
212237
213- fn to_pdl ( & self , m : & Map < String , Value > ) -> HashMap < String , PdlBlock > {
214- m. into_iter ( )
215- . map ( |( k, v) | {
216- (
217- k. clone ( ) ,
218- match v {
219- Value :: String ( s) => PdlBlock :: String ( s. clone ( ) ) ,
220- Value :: Number ( n) => PdlBlock :: Number ( n. clone ( ) ) ,
221- x => {
222- eprintln ! ( "Unhandled arg value {:?}" , x) ;
223- "error" . into ( )
224- }
225- } ,
226- )
227- } )
228- . collect ( )
238+ res
229239 }
230240
231241 fn to_ollama_model_options (
@@ -428,19 +438,41 @@ impl<'a> Interpreter<'a> {
428438 }
429439
430440 // Run a PdlBlock::Repeat
431- async fn run_repeat ( & mut self , block : & PdlRepeatBlock , _context : Context ) -> Interpretation {
432- let for_ = block
441+ async fn run_repeat ( & mut self , block : & PdlRepeatBlock , context : Context ) -> Interpretation {
442+ // { i:[1,2,3], j: [4,5,6]} -> ([i,j], [[1,2,3],[4,5,6]])
443+ // let (variables, values): (Vec<_>, Vec<Vec<_>>) = block
444+ // .into_iter()
445+ // .unzip();
446+ let map = block
433447 . for_
434448 . iter ( )
435- . map ( |( var, values) | ( var, self . eval :: < PdlBlock > ( & values) ) ) ;
449+ . map ( |( var, values) | match self . eval_list_or_string ( values) {
450+ Ok ( value) => Ok ( ( var. clone ( ) , value) ) ,
451+ Err ( e) => Err ( e) ,
452+ } )
453+ . collect :: < Result < HashMap < _ , _ > , _ > > ( ) ?;
436454
437455 if self . debug {
438- eprintln ! ( "Repeat {:?}" , & for_ ) ;
456+ eprintln ! ( "Repeat {:?}" , map ) ;
439457 }
440- Ok ( (
441- vec ! [ ChatMessage :: user( "TODO" . into( ) ) ] ,
442- PdlBlock :: Repeat ( block. clone ( ) ) ,
443- ) )
458+
459+ let mut messages = vec ! [ ] ;
460+ let mut trace = vec ! [ ] ;
461+ if let Some ( n) = map. iter ( ) . map ( |( _, v) | v. len ( ) ) . min ( ) {
462+ for iter in 0 ..n {
463+ let scope: HashMap < String , Value > = map
464+ . iter ( )
465+ . map ( |( k, v) | ( k. clone ( ) , v[ iter] . clone ( ) ) )
466+ . collect ( ) ;
467+ self . extend_scope_with_map ( scope) ;
468+ let ( ms, t) = self . run_quiet ( & block. repeat , context. clone ( ) ) . await ?;
469+ messages. extend ( ms) ;
470+ trace. push ( t) ;
471+ self . scope . pop ( ) ;
472+ }
473+ }
474+
475+ Ok ( ( messages, PdlBlock :: Repeat ( block. clone ( ) ) ) )
444476 }
445477
446478 fn to_ollama_role ( & self , role : & Role ) -> MessageRole {
@@ -462,7 +494,18 @@ impl<'a> Interpreter<'a> {
462494 }
463495 }
464496
465- fn extend_scope_with_map ( & mut self , map : & Option < HashMap < String , PdlBlock > > ) {
497+ fn extend_scope_with_map ( & mut self , new_scope : HashMap < String , Value > ) {
498+ self . scope . push ( new_scope) ;
499+ }
500+
501+ fn extend_scope_with_json_map ( & mut self , new_scope : Map < String , Value > ) {
502+ let mut scope = self . scope . last ( ) . unwrap_or ( & HashMap :: new ( ) ) . clone ( ) ;
503+ // TODO figure out iterators
504+ scope. extend ( new_scope. into_iter ( ) . collect :: < HashMap < String , Value > > ( ) ) ;
505+ self . extend_scope_with_map ( scope) ;
506+ }
507+
508+ fn extend_scope_with_block_map ( & mut self , map : & Option < HashMap < String , PdlBlock > > ) {
466509 let cur_scope = self . scope . last ( ) . unwrap_or ( & HashMap :: new ( ) ) . clone ( ) ;
467510 let new_scope = match map {
468511 Some ( defs) => {
@@ -479,7 +522,7 @@ impl<'a> Interpreter<'a> {
479522 None => cur_scope,
480523 } ;
481524
482- self . scope . push ( new_scope) ;
525+ self . extend_scope_with_map ( new_scope) ;
483526 }
484527
485528 // Run a PdlBlock::Text
@@ -498,7 +541,7 @@ impl<'a> Interpreter<'a> {
498541 let mut output_messages = vec ! [ ] ;
499542 let mut output_blocks = vec ! [ ] ;
500543
501- self . extend_scope_with_map ( & block. defs ) ;
544+ self . extend_scope_with_block_map ( & block. defs ) ;
502545 let mut iter = block. text . iter ( ) ;
503546 while let Some ( block) = iter. next ( ) {
504547 // run each element of the Text block
0 commit comments