Created
January 6, 2025 21:49
-
-
Save Eastwooder/100df7445b491fec09668d015c6ea0f1 to your computer and use it in GitHub Desktop.
Using Starlark as plugin language for rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [package] | |
| name = "starlark-playground" | |
| version = "0.1.0" | |
| edition = "2021" | |
| [dependencies] | |
| allocative = "0.3.4" | |
| indoc = "2.0.5" | |
| starlark = "0.13.0" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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, | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment