Skip to content

Commit 1918c4b

Browse files
committed
read struct from file and read from path relative fixes
Signed-off-by: Nick Mitchell <[email protected]>
1 parent 175d550 commit 1918c4b

File tree

5 files changed

+113
-41
lines changed

5 files changed

+113
-41
lines changed

pdl-live-react/src-tauri/src/pdl/ast.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ pub enum PdlParser {
2020
#[serde(rename = "json")]
2121
Json,
2222
/*#[serde(rename = "jsonl")]
23-
Jsonl,
23+
Jsonl,*/
2424
#[serde(rename = "yaml")]
25-
Yaml,*/
25+
Yaml,
2626
}
2727

2828
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -294,12 +294,20 @@ pub struct PythonCodeBlock {
294294
/// ```
295295
#[derive(Serialize, Deserialize, Debug, Clone)]
296296
pub struct ReadBlock {
297-
// Name of the file to read. If `None`, read the standard input.
297+
/// Name of the file to read. If `None`, read the standard input.
298298
pub read: Value,
299-
// Name of the file to read. If `None`, read the standard input.
299+
300+
/// Name of the file to read. If `None`, read the standard input.
300301
pub message: Option<String>,
301-
// Indicate if one or multiple lines should be read.
302+
303+
/// Indicate if one or multiple lines should be read.
302304
pub multiline: Option<bool>,
305+
306+
#[serde(skip_serializing_if = "Option::is_none")]
307+
pub def: Option<String>,
308+
309+
#[serde(skip_serializing_if = "Option::is_none")]
310+
pub parser: Option<PdlParser>,
303311
}
304312

305313
#[derive(Serialize, Deserialize, Debug, Clone)]

pdl-live-react/src-tauri/src/pdl/interpreter.rs

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// use ::std::cell::LazyCell;
22
use ::std::collections::HashMap;
3-
use std::sync::{Arc, Mutex};
4-
// use ::std::env::current_dir;
3+
use ::std::env::current_dir;
54
use ::std::error::Error;
65
use ::std::fs::{read_to_string as read_file_to_string, File};
7-
// use ::std::path::PathBuf;
6+
use ::std::path::PathBuf;
7+
use std::sync::{Arc, Mutex};
88

99
use async_recursion::async_recursion;
1010
use minijinja::{syntax::SyntaxConfig, Environment};
@@ -31,13 +31,14 @@ use crate::pdl::ast::{
3131

3232
type Context = Vec<ChatMessage>;
3333
type Scope = HashMap<String, Value>;
34-
type Interpretation = Result<(Context, PdlBlock), Box<dyn Error + Send + Sync>>;
34+
type PdlError = Box<dyn Error + Send + Sync>;
35+
type Interpretation = Result<(Context, PdlBlock), PdlError>;
3536
type InterpretationSync = Result<(Context, PdlBlock), Box<dyn Error>>;
3637

3738
struct Interpreter<'a> {
3839
// batch: u32,
3940
// role: Role,
40-
// cwd: Box<PathBuf>,
41+
cwd: PathBuf,
4142
// id_stack: Vec<String>,
4243
jinja_env: Environment<'a>,
4344
// rt: Runtime,
@@ -60,7 +61,7 @@ impl<'a> Interpreter<'a> {
6061
Self {
6162
// batch: 0,
6263
// role: Role::User,
63-
// cwd: Box::new(current_dir().unwrap_or(PathBuf::from("/"))),
64+
cwd: current_dir().unwrap_or(PathBuf::from("/")),
6465
// id_stack: vec![],
6566
jinja_env: jinja_env,
6667
// rt: Runtime::new().unwrap(),
@@ -113,11 +114,11 @@ impl<'a> Interpreter<'a> {
113114
self.run_with_emit(program, context, self.emit).await
114115
}
115116

116-
// Evaluate String as a Jinja2 expression
117+
/// Evaluate String as a Jinja2 expression
117118
fn eval<T: serde::de::DeserializeOwned + ::std::convert::From<String>>(
118119
&self,
119120
expr: &String,
120-
) -> Result<T, Box<dyn Error + Send + Sync>> {
121+
) -> Result<T, PdlError> {
121122
let result = self
122123
.jinja_env
123124
.render_str(expr.as_str(), self.scope.last().unwrap_or(&HashMap::new()))?;
@@ -135,7 +136,7 @@ impl<'a> Interpreter<'a> {
135136
}))
136137
}
137138

138-
fn eval_complex(&self, expr: &Value) -> Result<Value, Box<dyn Error + Send + Sync>> {
139+
fn eval_complex(&self, expr: &Value) -> Result<Value, PdlError> {
139140
match expr {
140141
Value::String(s) => self.eval(s),
141142
Value::Array(a) => Ok(Value::Array(
@@ -155,11 +156,8 @@ impl<'a> Interpreter<'a> {
155156
}
156157
}
157158

158-
// Evaluate an string or list of Values into a list of Values
159-
fn eval_list_or_string(
160-
&self,
161-
expr: &ListOrString,
162-
) -> Result<Vec<Value>, Box<dyn Error + Send + Sync>> {
159+
/// Evaluate an string or list of Values into a list of Values
160+
fn eval_list_or_string(&self, expr: &ListOrString) -> Result<Vec<Value>, PdlError> {
163161
match expr {
164162
ListOrString::String(s) => match self.eval::<Value>(s)? {
165163
Value::Array(a) => Ok(a),
@@ -172,7 +170,7 @@ impl<'a> Interpreter<'a> {
172170
}
173171
}
174172

175-
// Run a PdlBlock::String
173+
/// Run a PdlBlock::String
176174
async fn run_string(&self, msg: &String, _context: Context) -> Interpretation {
177175
let trace = self.eval::<PdlBlock>(msg)?;
178176
if self.debug {
@@ -187,16 +185,46 @@ impl<'a> Interpreter<'a> {
187185
Ok((messages, trace))
188186
}
189187

190-
// Run a PdlBlock::Read
191-
async fn run_read(&self, block: &ReadBlock, _context: Context) -> Interpretation {
188+
fn path_to(&self, file_path: &String) -> PathBuf {
189+
let mut path = self.cwd.clone();
190+
path.push(file_path);
191+
path
192+
}
193+
194+
fn def(
195+
&mut self,
196+
variable: &Option<String>,
197+
value: &String,
198+
parser: &Option<PdlParser>,
199+
) -> Result<(), PdlError> {
200+
if let Some(def) = &variable {
201+
let result = if let Some(parser) = parser {
202+
self.parse_result(parser, &value)?
203+
} else {
204+
Value::from(value.clone()) // TODO
205+
};
206+
207+
if let Some(scope) = self.scope.last_mut() {
208+
if self.debug {
209+
eprintln!("Def {} -> {}", def, result);
210+
}
211+
scope.insert(def.clone(), result);
212+
}
213+
}
214+
215+
Ok(())
216+
}
217+
218+
/// Run a PdlBlock::Read
219+
async fn run_read(&mut self, block: &ReadBlock, _context: Context) -> Interpretation {
192220
let trace = block.clone();
193221

194222
if let Some(message) = &block.message {
195223
println!("{}", message);
196224
}
197225

198226
let buffer = match &block.read {
199-
Value::String(file_path) => Ok(read_file_to_string(file_path)?),
227+
Value::String(file_path) => Ok(read_file_to_string(self.path_to(file_path))?),
200228
Value::Null => {
201229
let mut buffer = String::new();
202230
::std::io::stdin().read_line(&mut buffer)?;
@@ -208,10 +236,12 @@ impl<'a> Interpreter<'a> {
208236
))),
209237
}?;
210238

239+
self.def(&block.def, &buffer, &block.parser)?;
240+
211241
Ok((vec![ChatMessage::user(buffer)], PdlBlock::Read(trace)))
212242
}
213243

214-
// Run a PdlBlock::Call
244+
/// Run a PdlBlock::Call
215245
async fn run_call(&mut self, block: &CallBlock, context: Context) -> Interpretation {
216246
if self.debug {
217247
eprintln!("Call {:?}({:?})", block.call, block.args);
@@ -239,7 +269,7 @@ impl<'a> Interpreter<'a> {
239269
res
240270
}
241271

242-
// Run a PdlBlock::Call
272+
/// Run a PdlBlock::Call
243273
async fn run_if(&mut self, block: &IfBlock, context: Context) -> Interpretation {
244274
if self.debug {
245275
eprintln!("If {:?}({:?})", block.condition, block.then);
@@ -302,7 +332,7 @@ impl<'a> Interpreter<'a> {
302332
}
303333
}
304334

305-
// Run a PdlBlock::PythonCode
335+
/// Run a PdlBlock::PythonCode
306336
async fn run_python_code(
307337
&mut self,
308338
block: &PythonCodeBlock,
@@ -351,7 +381,7 @@ impl<'a> Interpreter<'a> {
351381
})
352382
}
353383

354-
// Run a PdlBlock::Model
384+
/// Run a PdlBlock::Model
355385
async fn run_model(&mut self, block: &ModelBlock, context: Context) -> Interpretation {
356386
match &block.model {
357387
pdl_model
@@ -466,7 +496,7 @@ impl<'a> Interpreter<'a> {
466496
}
467497
}
468498

469-
// Run a PdlBlock::Repeat
499+
/// Run a PdlBlock::Repeat
470500
async fn run_repeat(&mut self, block: &RepeatBlock, context: Context) -> Interpretation {
471501
// { i:[1,2,3], j: [4,5,6]} -> ([i,j], [[1,2,3],[4,5,6]])
472502
// let (variables, values): (Vec<_>, Vec<Vec<_>>) = block
@@ -513,13 +543,10 @@ impl<'a> Interpreter<'a> {
513543
}
514544
}
515545

516-
fn parse_result(
517-
&self,
518-
parser: &PdlParser,
519-
result: &String,
520-
) -> Result<Value, Box<dyn Error + Send + Sync>> {
546+
fn parse_result(&self, parser: &PdlParser, result: &String) -> Result<Value, PdlError> {
521547
match parser {
522548
PdlParser::Json => Ok(from_str(result)?),
549+
PdlParser::Yaml => Ok(from_yaml_str(result)?),
523550
}
524551
}
525552

@@ -554,7 +581,7 @@ impl<'a> Interpreter<'a> {
554581
self.extend_scope_with_map(new_scope);
555582
}
556583

557-
// Run a PdlBlock::Text
584+
/// Run a PdlBlock::Text
558585
async fn run_text(&mut self, block: &TextBlock, context: Context) -> Interpretation {
559586
if self.debug {
560587
eprintln!(
@@ -615,19 +642,25 @@ impl<'a> Interpreter<'a> {
615642
}
616643
}
617644

618-
pub async fn run(program: &PdlBlock, debug: bool) -> Interpretation {
645+
pub async fn run(program: &PdlBlock, cwd: Option<PathBuf>, debug: bool) -> Interpretation {
619646
let mut interpreter = Interpreter::new();
620647
interpreter.debug = debug;
648+
if let Some(cwd) = cwd {
649+
interpreter.cwd = cwd
650+
};
621651
interpreter.run(&program, vec![]).await
622652
}
623653

624-
pub fn run_sync(program: &PdlBlock, debug: bool) -> InterpretationSync {
625-
tauri::async_runtime::block_on(run(program, debug))
654+
pub fn run_sync(program: &PdlBlock, cwd: Option<PathBuf>, debug: bool) -> InterpretationSync {
655+
tauri::async_runtime::block_on(run(program, cwd, debug))
626656
.map_err(|err| Box::<dyn ::std::error::Error>::from(err.to_string()))
627657
}
628658

629659
pub async fn run_file(source_file_path: &str, debug: bool) -> Interpretation {
630-
run(&from_reader(File::open(source_file_path)?)?, debug).await
660+
let cwd = PathBuf::from(source_file_path)
661+
.parent()
662+
.and_then(|cwd| Some(cwd.to_path_buf()));
663+
run(&from_reader(File::open(source_file_path)?)?, cwd, debug).await
631664
}
632665

633666
pub fn run_file_sync(source_file_path: &str, debug: bool) -> InterpretationSync {
@@ -636,7 +669,7 @@ pub fn run_file_sync(source_file_path: &str, debug: bool) -> InterpretationSync
636669
}
637670

638671
pub async fn run_string(source: &str, debug: bool) -> Interpretation {
639-
run(&from_yaml_str(source)?, debug).await
672+
run(&from_yaml_str(source)?, None, debug).await
640673
}
641674

642675
pub async fn run_json(source: Value, debug: bool) -> Interpretation {

pdl-live-react/src-tauri/src/pdl/interpreter_tests.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod tests {
1515

1616
#[test]
1717
fn string() -> Result<(), Box<dyn Error>> {
18-
let (messages, _) = run(&"hello".into(), false)?;
18+
let (messages, _) = run(&"hello".into(), None, false)?;
1919
assert_eq!(messages.len(), 1);
2020
assert_eq!(messages[0].role, MessageRole::User);
2121
assert_eq!(messages[0].content, "hello");
@@ -26,6 +26,7 @@ mod tests {
2626
fn single_model_via_input() -> Result<(), Box<dyn Error>> {
2727
let (messages, _) = run(
2828
&PdlBlock::Model(ModelBlock::new(DEFAULT_MODEL).input_str("hello").build()),
29+
None,
2930
false,
3031
)?;
3132
assert_eq!(messages.len(), 1);
@@ -208,7 +209,7 @@ mod tests {
208209
}
209210

210211
#[test]
211-
fn text_read_file() -> Result<(), Box<dyn Error>> {
212+
fn text_read_file_text() -> Result<(), Box<dyn Error>> {
212213
let program = json!({
213214
"message": "Read a file",
214215
"read":"./tests/data/foo.txt"
@@ -221,6 +222,29 @@ mod tests {
221222
Ok(())
222223
}
223224

225+
#[test]
226+
fn text_read_file_struct() -> Result<(), Box<dyn Error>> {
227+
let program = json!({
228+
"text": [
229+
{ "read": "./tests/data/struct.yaml", "def": "struct", "parser": "yaml" },
230+
"${ struct.a.b }"
231+
]
232+
});
233+
234+
let (messages, _) = run_json(program, false)?;
235+
assert_eq!(messages.len(), 2);
236+
assert_eq!(messages[0].role, MessageRole::User);
237+
assert_eq!(
238+
messages[0].content,
239+
"a:
240+
b: 3
241+
"
242+
);
243+
assert_eq!(messages[1].role, MessageRole::User);
244+
assert_eq!(messages[1].content, "3");
245+
Ok(())
246+
}
247+
224248
#[test]
225249
fn text_repeat_numbers_1d() -> Result<(), Box<dyn Error>> {
226250
let program = json!({
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
text:
2+
- read: ../data/struct.yaml
3+
def: struct
4+
parser: yaml
5+
- ${ struct.a.b }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a:
2+
b: 3

0 commit comments

Comments
 (0)