Skip to content

Commit fb541af

Browse files
committed
empty blocks, import blocks, and chained cwd for includes, too
Signed-off-by: Nick Mitchell <[email protected]>
1 parent 139393b commit fb541af

File tree

3 files changed

+88
-13
lines changed

3 files changed

+88
-13
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,13 +524,27 @@ pub struct IncludeBlock {
524524
pub include: String,
525525
}
526526

527+
/// Import a PDL file
528+
#[derive(Serialize, Deserialize, Debug, Clone)]
529+
pub struct ImportBlock {
530+
/// Name of the file to include.
531+
pub import: String,
532+
}
533+
534+
/// Block containing only defs
535+
#[derive(Serialize, Deserialize, Debug, Clone)]
536+
pub struct EmptyBlock {
537+
pub defs: IndexMap<String, PdlBlock>,
538+
}
539+
527540
#[derive(Serialize, Deserialize, Debug, Clone)]
528541
#[serde(untagged)]
529542
pub enum PdlBlock {
530543
Bool(bool),
531544
Number(Number),
532545
String(String),
533546
If(IfBlock),
547+
Import(ImportBlock),
534548
Include(IncludeBlock),
535549
Data(DataBlock),
536550
Object(ObjectBlock),
@@ -544,6 +558,9 @@ pub enum PdlBlock {
544558
Function(FunctionBlock),
545559
PythonCode(PythonCodeBlock),
546560
Read(ReadBlock),
561+
562+
// must be last to prevent serde from aggressively matching on it, since other block types also (may) have a `defs`
563+
Empty(EmptyBlock),
547564
}
548565

549566
impl From<&str> for PdlBlock {

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

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ use serde_json::{from_str, to_string, Value};
2525
use serde_norway::{from_reader, from_str as from_yaml_str};
2626

2727
use crate::pdl::ast::{
28-
ArrayBlock, CallBlock, Closure, DataBlock, FunctionBlock, IfBlock, IncludeBlock, ListOrString,
29-
MessageBlock, ModelBlock, ObjectBlock, PdlBlock, PdlParser, PdlResult, PdlUsage,
30-
PythonCodeBlock, ReadBlock, RepeatBlock, Role, Scope, SequencingBlock, StringOrBoolean,
28+
ArrayBlock, CallBlock, Closure, DataBlock, EmptyBlock, FunctionBlock, IfBlock, ImportBlock,
29+
IncludeBlock, ListOrString, MessageBlock, ModelBlock, ObjectBlock, PdlBlock, PdlParser,
30+
PdlResult, PdlUsage, PythonCodeBlock, ReadBlock, RepeatBlock, Role, Scope, SequencingBlock,
31+
StringOrBoolean,
3132
};
3233

3334
type Context = Vec<ChatMessage>;
@@ -99,7 +100,9 @@ impl<'a> Interpreter<'a> {
99100
)),
100101
PdlBlock::String(s) => self.run_string(s, context).await,
101102
PdlBlock::Call(block) => self.run_call(block, context).await,
103+
PdlBlock::Empty(block) => self.run_empty(block, context).await,
102104
PdlBlock::If(block) => self.run_if(block, context).await,
105+
PdlBlock::Import(block) => self.run_import(block, context).await,
103106
PdlBlock::Include(block) => self.run_include(block, context).await,
104107
PdlBlock::Model(block) => self.run_model(block, context).await,
105108
PdlBlock::Data(block) => self.run_data(block, context).await,
@@ -230,7 +233,11 @@ impl<'a> Interpreter<'a> {
230233
fn path_to(&self, file_path: &String) -> PathBuf {
231234
let mut path = self.cwd.clone();
232235
path.push(file_path);
233-
path
236+
if path.extension().is_none() {
237+
path.with_extension("pdl")
238+
} else {
239+
path
240+
}
234241
}
235242

236243
fn def(
@@ -299,6 +306,7 @@ impl<'a> Interpreter<'a> {
299306
async fn run_call(&mut self, block: &CallBlock, context: Context) -> Interpretation {
300307
if self.debug {
301308
eprintln!("Call {:?}({:?})", block.call, block.args);
309+
eprintln!("Call scope {:?}", self.scope.last());
302310
}
303311

304312
let res = match self.eval(&block.call)? {
@@ -328,6 +336,21 @@ impl<'a> Interpreter<'a> {
328336
res
329337
}
330338

339+
/// Run a PdlBlock::Empty
340+
async fn run_empty(&mut self, block: &EmptyBlock, _context: Context) -> Interpretation {
341+
if self.debug {
342+
eprintln!("Empty");
343+
}
344+
345+
let trace = block.clone();
346+
self.process_defs(&Some(block.defs.clone())).await?;
347+
Ok((
348+
PdlResult::Dict(self.scope.last().unwrap_or(&HashMap::new()).clone()),
349+
vec![],
350+
PdlBlock::Empty(trace),
351+
))
352+
}
353+
331354
/// Run a PdlBlock::Call
332355
async fn run_if(&mut self, block: &IfBlock, context: Context) -> Interpretation {
333356
if self.debug {
@@ -362,8 +385,30 @@ impl<'a> Interpreter<'a> {
362385
eprintln!("Include {:?}", block.include);
363386
}
364387

365-
self.run_quiet(&parse_file(&self.path_to(&block.include))?, context.clone())
366-
.await
388+
let path = self.path_to(&block.include);
389+
let old_cwd = self.cwd.clone();
390+
if let Some(cwd) = path.parent() {
391+
self.cwd = cwd.to_path_buf()
392+
}
393+
let res = self.run_quiet(&parse_file(&path)?, context.clone()).await;
394+
self.cwd = old_cwd;
395+
res
396+
}
397+
398+
/// Run a PdlBlock::Import
399+
async fn run_import(&mut self, block: &ImportBlock, context: Context) -> Interpretation {
400+
if self.debug {
401+
eprintln!("Import {:?}", block.import);
402+
}
403+
404+
let path = self.path_to(&block.import);
405+
let old_cwd = self.cwd.clone();
406+
if let Some(cwd) = path.parent() {
407+
self.cwd = cwd.to_path_buf()
408+
}
409+
let res = self.run_quiet(&parse_file(&path)?, context.clone()).await;
410+
self.cwd = old_cwd;
411+
res
367412
}
368413

369414
fn to_ollama_model_options(

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ mod tests {
458458
}
459459

460460
#[test]
461-
fn text_include() -> Result<(), Box<dyn Error>> {
461+
fn include() -> Result<(), Box<dyn Error>> {
462462
let program = json!({
463463
"include": "./tests/cli/call-with-args.pdl"
464464
});
@@ -471,7 +471,7 @@ mod tests {
471471
}
472472

473473
#[test]
474-
fn text_data_1() -> Result<(), Box<dyn Error>> {
474+
fn data_1() -> Result<(), Box<dyn Error>> {
475475
let program = json!({
476476
"include": "./tests/cli/data1.pdl"
477477
});
@@ -484,7 +484,7 @@ mod tests {
484484
}
485485

486486
#[test]
487-
fn text_data_2() -> Result<(), Box<dyn Error>> {
487+
fn data_2() -> Result<(), Box<dyn Error>> {
488488
let program = json!({
489489
"include": "./tests/cli/data2.pdl"
490490
});
@@ -497,7 +497,7 @@ mod tests {
497497
}
498498

499499
#[test]
500-
fn text_data_3() -> Result<(), Box<dyn Error>> {
500+
fn data_3() -> Result<(), Box<dyn Error>> {
501501
let program = json!({
502502
"include": "./tests/cli/data3.pdl"
503503
});
@@ -509,8 +509,8 @@ mod tests {
509509
Ok(())
510510
}
511511

512-
/*#[test]
513-
fn text_data_4() -> Result<(), Box<dyn Error>> {
512+
#[test]
513+
fn data_4() -> Result<(), Box<dyn Error>> {
514514
let program = json!({
515515
"include": "./tests/cli/data4.pdl"
516516
});
@@ -520,5 +520,18 @@ mod tests {
520520
assert_eq!(messages[0].role, MessageRole::User);
521521
assert_eq!(messages[0].content, "yyyyxxxx3true");
522522
Ok(())
523-
}*/
523+
}
524+
525+
#[test]
526+
fn import_1() -> Result<(), Box<dyn Error>> {
527+
let program = json!({
528+
"include": "../../examples/tutorial/import.pdl"
529+
});
530+
531+
let (_, messages, _) = run_json(program, false)?;
532+
assert_eq!(messages.len(), 1);
533+
assert_eq!(messages[0].role, MessageRole::User);
534+
assert_eq!(messages[0].content, "Bye!");
535+
Ok(())
536+
}
524537
}

0 commit comments

Comments
 (0)