Skip to content

Instantly share code, notes, and snippets.

@Eastwooder
Created January 6, 2025 21:49
Show Gist options
  • Save Eastwooder/100df7445b491fec09668d015c6ea0f1 to your computer and use it in GitHub Desktop.
Save Eastwooder/100df7445b491fec09668d015c6ea0f1 to your computer and use it in GitHub Desktop.

Revisions

  1. Eastwooder created this gist Jan 6, 2025.
    9 changes: 9 additions & 0 deletions Cargo.toml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    [package]
    name = "starlark-playground"
    version = "0.1.0"
    edition = "2021"

    [dependencies]
    allocative = "0.3.4"
    indoc = "2.0.5"
    starlark = "0.13.0"
    89 changes: 89 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    use allocative::Allocative;
    use indoc::indoc;
    use starlark::any::ProvidesStaticType;
    use starlark::environment::{GlobalsBuilder, Module};
    use starlark::eval::Evaluator;
    use starlark::syntax::{AstModule, Dialect};
    use starlark::values::none::NoneType;
    use starlark::values::{starlark_value, Heap, NoSerialize, StarlarkValue, Value};
    use starlark::{starlark_module, starlark_simple_value};
    use std::cell::RefCell;
    use std::fmt::{Display, Formatter};

    fn main() -> starlark::Result<()> {
    let content = indoc! {"
    def my_loop(members):
    for item in members:
    emit(item)
    emit(fetch().name)
    my_loop(fetch().members)
    "};
    let ast = AstModule::parse("complex.star", content.to_owned(), &Dialect::Standard)?;
    let globals = GlobalsBuilder::new().with(starlark_fetch).build();
    let module = Module::new();
    let store = Store::default();
    {
    let mut eval = Evaluator::new(&module);
    eval.extra = Some(&store);
    let _ = eval.eval_module(ast, &globals)?;
    }
    for emitted in &*store.0.borrow() {
    println!("emitted: {emitted}");
    }
    Ok(())
    }

    // Define a store in which to accumulate JSON strings
    #[derive(Debug, ProvidesStaticType, Default)]
    struct Store(RefCell<Vec<String>>);

    impl Store {
    fn add(&self, x: String) {
    self.0.borrow_mut().push(x)
    }
    }

    #[starlark_module]
    fn starlark_fetch(builder: &mut GlobalsBuilder) {
    fn fetch(eval: &mut Evaluator) -> starlark::Result<Extr> {
    Ok(Extr {
    name: "test".to_string(),
    members: vec!["a".to_string(), "b".to_string()],
    })
    }
    fn emit(x: Value, eval: &mut Evaluator) -> starlark::Result<NoneType> {
    // We modify extra (which we know is a Store) and add the JSON of the
    // value the user gave.
    eval.extra
    .unwrap()
    .downcast_ref::<Store>()
    .unwrap()
    .add(x.to_json()?);
    Ok(NoneType)
    }
    }

    #[derive(Debug, Clone, ProvidesStaticType, NoSerialize, Allocative)]
    pub struct Extr {
    pub name: String,
    pub members: Vec<String>,
    }
    starlark_simple_value!(Extr);

    impl Display for Extr {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    write!(f, "Extr[name={name}]", name = self.name)
    }
    }

    #[starlark_value(type = "Extr")]
    impl<'v> StarlarkValue<'v> for Extr {
    fn get_attr(&self, attribute: &str, heap: &'v Heap) -> Option<Value<'v>> {
    match attribute {
    "name" => Some(heap.alloc(self.name.clone())),
    "members" => Some(heap.alloc(self.members.clone())),
    _ => None,
    }
    }
    }