mirror of https://git.meli.delivery/meli/meli
wip
parent
11a0586d56
commit
b2a6e15e76
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* ____
|
||||
*
|
||||
* Copyright ____ Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of ____.
|
||||
*
|
||||
* ____ is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ____ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ____. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark() {
|
||||
use starlark::{
|
||||
environment::{Globals, Module},
|
||||
eval::Evaluator,
|
||||
syntax::{AstModule, Dialect},
|
||||
values::Value,
|
||||
};
|
||||
let content = r#"
|
||||
def hello():
|
||||
return "hello"
|
||||
hello() + " world!"
|
||||
"#;
|
||||
|
||||
// We first parse the content, giving a filename and the Starlark
|
||||
// `Dialect` we'd like to use (we pick standard).
|
||||
let ast: AstModule =
|
||||
AstModule::parse("hello_world.star", content.to_owned(), &Dialect::Standard).unwrap();
|
||||
|
||||
// We create a `Globals`, defining the standard library functions available.
|
||||
// The `standard` function uses those defined in the Starlark specification.
|
||||
let globals: Globals = Globals::standard();
|
||||
|
||||
// We create a `Module`, which stores the global variables for our calculation.
|
||||
let module: Module = Module::new();
|
||||
|
||||
// We create an evaluator, which controls how evaluation occurs.
|
||||
let mut eval: Evaluator = Evaluator::new(&module);
|
||||
|
||||
// And finally we evaluate the code using the evaluator.
|
||||
let res: Value = eval.eval_module(ast, &globals).unwrap();
|
||||
assert_eq!(res.unpack_str(), Some("hello world!"));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_2() {
|
||||
use starlark::{
|
||||
environment::{GlobalsBuilder, Module},
|
||||
eval::Evaluator,
|
||||
starlark_module,
|
||||
syntax::{AstModule, Dialect},
|
||||
};
|
||||
|
||||
// This defines the function that is visible to Starlark
|
||||
#[starlark_module]
|
||||
fn starlark_quadratic(builder: &mut GlobalsBuilder) {
|
||||
fn quadratic(a: i32, b: i32, c: i32, x: i32) -> starlark::Result<i32> {
|
||||
Ok(a * x * x + b * x + c)
|
||||
}
|
||||
}
|
||||
|
||||
// We build our globals to make the function available in Starlark
|
||||
let globals = GlobalsBuilder::new().with(starlark_quadratic).build();
|
||||
let module = Module::new();
|
||||
let mut eval = Evaluator::new(&module);
|
||||
|
||||
// Let's test calling the function from Starlark code
|
||||
let starlark_code = r#"
|
||||
quadratic(4, 2, 1, x = 8)
|
||||
"#;
|
||||
|
||||
let ast = AstModule::parse(
|
||||
"quadratic.star",
|
||||
starlark_code.to_owned(),
|
||||
&Dialect::Standard,
|
||||
)
|
||||
.unwrap();
|
||||
let res = eval.eval_module(ast, &globals).unwrap();
|
||||
assert_eq!(res.unpack_i32(), Some(273)); // Verify that we got an `int`
|
||||
// return value of 4 * 8^2 + 2 * 8
|
||||
// + 1 = 273
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_3() {
|
||||
use std::cell::RefCell;
|
||||
|
||||
use starlark::{
|
||||
any::ProvidesStaticType,
|
||||
environment::{GlobalsBuilder, Module},
|
||||
eval::Evaluator,
|
||||
starlark_module,
|
||||
syntax::{AstModule, Dialect},
|
||||
values::{none::NoneType, Value},
|
||||
};
|
||||
|
||||
let content = r#"
|
||||
emit(1)
|
||||
emit(["test"])
|
||||
emit({"x": "y"})
|
||||
"#;
|
||||
|
||||
// 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_emit(builder: &mut GlobalsBuilder) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
let ast = AstModule::parse("json.star", content.to_owned(), &Dialect::Standard).unwrap();
|
||||
// We build our globals adding some functions we wrote
|
||||
let globals = GlobalsBuilder::new().with(starlark_emit).build();
|
||||
let module = Module::new();
|
||||
let store = Store::default();
|
||||
{
|
||||
let mut eval = Evaluator::new(&module);
|
||||
// We add a reference to our store
|
||||
eval.extra = Some(&store);
|
||||
eval.eval_module(ast, &globals).unwrap();
|
||||
}
|
||||
assert_eq!(&*store.0.borrow(), &["1", "[\"test\"]", "{\"x\":\"y\"}"]);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_4() {
|
||||
use starlark::{
|
||||
environment::{Globals, Module},
|
||||
eval::Evaluator,
|
||||
syntax::{AstModule, Dialect, DialectTypes},
|
||||
};
|
||||
|
||||
let content = r#"
|
||||
def takes_int(x: int):
|
||||
pass
|
||||
takes_int("test")
|
||||
"#;
|
||||
|
||||
// Make the dialect enable types
|
||||
let dialect = Dialect {
|
||||
enable_types: DialectTypes::Enable,
|
||||
..Dialect::Standard
|
||||
};
|
||||
// We could equally have done `dialect = Dialect::Extended`.
|
||||
let ast = AstModule::parse("json.star", content.to_owned(), &dialect).unwrap();
|
||||
let globals = Globals::standard();
|
||||
let module = Module::new();
|
||||
let mut eval = Evaluator::new(&module);
|
||||
let res = eval.eval_module(ast, &globals);
|
||||
// We expect this to fail, since it is a type violation
|
||||
assert!(res
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Value `test` of type `string` does not match the type annotation `int`"));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_5() {
|
||||
use starlark::{
|
||||
environment::{FrozenModule, Globals, Module},
|
||||
eval::{Evaluator, ReturnFileLoader},
|
||||
syntax::{AstModule, Dialect},
|
||||
};
|
||||
|
||||
// Get the file contents (for the demo), in reality use `AstModule::parse_file`.
|
||||
fn get_source(file: &str) -> &str {
|
||||
match file {
|
||||
"a.star" => "a = 7",
|
||||
"b.star" => "b = 6",
|
||||
_ => {
|
||||
r#"
|
||||
load('a.star', 'a')
|
||||
load('b.star', 'b')
|
||||
ab = a * b
|
||||
"#
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_module(file: &str) -> starlark::Result<FrozenModule> {
|
||||
let ast = AstModule::parse(file, get_source(file).to_owned(), &Dialect::Standard)?;
|
||||
|
||||
// We can get the loaded modules from `ast.loads`.
|
||||
// And ultimately produce a `loader` capable of giving those modules to
|
||||
// Starlark.
|
||||
let mut loads = Vec::new();
|
||||
for load in ast.loads() {
|
||||
loads.push((load.module_id.to_owned(), get_module(load.module_id)?));
|
||||
}
|
||||
let modules = loads.iter().map(|(a, b)| (a.as_str(), b)).collect();
|
||||
let mut loader = ReturnFileLoader { modules: &modules };
|
||||
|
||||
let globals = Globals::standard();
|
||||
let module = Module::new();
|
||||
{
|
||||
let mut eval = Evaluator::new(&module);
|
||||
eval.set_loader(&mut loader);
|
||||
eval.eval_module(ast, &globals)?;
|
||||
}
|
||||
// After creating a module we freeze it, preventing further mutation.
|
||||
// It can now be used as the input for other Starlark modules.
|
||||
Ok(module.freeze()?)
|
||||
}
|
||||
|
||||
let ab = get_module("ab.star").unwrap();
|
||||
assert_eq!(ab.get("ab").unwrap().unpack_i32(), Some(42));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_6() {
|
||||
use starlark::{
|
||||
environment::{Globals, Module},
|
||||
eval::Evaluator,
|
||||
syntax::{AstModule, Dialect},
|
||||
};
|
||||
|
||||
let content = r#"
|
||||
def quadratic(a, b, c, x):
|
||||
return a*x*x + b*x + c
|
||||
quadratic
|
||||
"#;
|
||||
|
||||
let ast = AstModule::parse("quadratic.star", content.to_owned(), &Dialect::Extended).unwrap();
|
||||
let globals = Globals::standard();
|
||||
let module = Module::new();
|
||||
let mut eval = Evaluator::new(&module);
|
||||
let quad = eval.eval_module(ast, &globals).unwrap();
|
||||
let heap = module.heap();
|
||||
let res = eval
|
||||
.eval_function(
|
||||
quad,
|
||||
&[heap.alloc(4), heap.alloc(2), heap.alloc(1)],
|
||||
&[("x", heap.alloc(8))],
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(res.unpack_i32(), Some(273));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_datetime_fmt() {
|
||||
use starlark::{
|
||||
environment::{GlobalsBuilder, Module},
|
||||
eval::Evaluator,
|
||||
starlark_module,
|
||||
syntax::{AstModule, Dialect},
|
||||
values::Value,
|
||||
};
|
||||
|
||||
let content = r#"
|
||||
def datetime_fmt():
|
||||
now_val = now()
|
||||
print("now returned ", now_val)
|
||||
n = since(now_val)
|
||||
print("since returned ", n)
|
||||
if n < 60 * 60:
|
||||
return "{} minute{} ago".format((n / (60)), ("" if n / 60 == 1 else "s"))
|
||||
elif n < 24 * 60 * 60:
|
||||
return "{} hour{} ago".format( n / (60 * 60), "" if n / (60 * 60) == 1 else "s")
|
||||
elif n < 7 * 24 * 60 * 60:
|
||||
return "{} day{} ago".format( n / (24 * 60 * 60), "" if n / (24 * 60 * 60) == 1 else "s")
|
||||
else:
|
||||
return "{}".format(n)
|
||||
datetime_fmt
|
||||
"#;
|
||||
|
||||
// This defines the function that is visible to Starlark
|
||||
#[starlark_module]
|
||||
fn starlark_datetime_fmt(builder: &mut GlobalsBuilder) {
|
||||
fn print(s: Value, val: u64) -> starlark::Result<i32> {
|
||||
let ss: &str = s.unpack_str().unwrap_or("");
|
||||
println!("{ss}{val}");
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
fn now() -> starlark::Result<u64> {
|
||||
let d = std::time::UNIX_EPOCH;
|
||||
let now: std::time::Duration = std::time::SystemTime::now().duration_since(d).unwrap();
|
||||
Ok(now.as_secs())
|
||||
}
|
||||
|
||||
fn since(epoch: u64) -> starlark::Result<u64> {
|
||||
let d = std::time::UNIX_EPOCH + std::time::Duration::from_secs(epoch);
|
||||
let now: std::time::Duration = std::time::SystemTime::now()
|
||||
.duration_since(d)
|
||||
.unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
|
||||
Ok(now.as_secs())
|
||||
}
|
||||
}
|
||||
|
||||
let ast =
|
||||
AstModule::parse("datetime_fmt.star", content.to_owned(), &Dialect::Extended).unwrap();
|
||||
let globals = GlobalsBuilder::new().with(starlark_datetime_fmt).build();
|
||||
let module = Module::new();
|
||||
let mut eval = Evaluator::new(&module);
|
||||
let quad = eval.eval_module(ast, &globals).unwrap();
|
||||
let res = eval.eval_function(quad, &[], &[]).unwrap();
|
||||
assert_eq!(
|
||||
res.unpack_str(),
|
||||
Some("0.0 minutes ago".to_string()).as_deref()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_starlark_7() {
|
||||
/*
|
||||
use starlark::starlark_module;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{self};
|
||||
|
||||
use allocative::Allocative;
|
||||
use starlark::environment::Globals;
|
||||
use starlark::environment::Module;
|
||||
use starlark::eval::Evaluator;
|
||||
use starlark::starlark_simple_value;
|
||||
use starlark::syntax::AstModule;
|
||||
use starlark::syntax::Dialect;
|
||||
use starlark::values::Heap;
|
||||
use starlark::values::NoSerialize;
|
||||
use starlark::values::ProvidesStaticType;
|
||||
use starlark::values::StarlarkValue;
|
||||
use starlark::values::Value;
|
||||
use starlark::values::ValueError;
|
||||
use starlark::values::ValueLike;
|
||||
use starlark_derive::starlark_value;
|
||||
|
||||
// Define complex numbers
|
||||
#[derive(Debug, PartialEq, Eq, ProvidesStaticType, NoSerialize, Allocative)]
|
||||
struct Complex {
|
||||
real: i32,
|
||||
imaginary: i32,
|
||||
}
|
||||
starlark_simple_value!(Complex);
|
||||
|
||||
impl Display for Complex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} + {}i", self.real, self.imaginary)
|
||||
}
|
||||
}
|
||||
|
||||
#[starlark_value(type = "complex")]
|
||||
impl<'v> StarlarkValue<'v> for Complex {
|
||||
// How we add them
|
||||
fn add(&self, rhs: Value<'v>, heap: &'v Heap) -> Option<starlark::Result<Value<'v>>> {
|
||||
if let Some(rhs) = rhs.downcast_ref::<Self>() {
|
||||
Some(Ok(heap.alloc(Complex {
|
||||
real: self.real + rhs.real,
|
||||
imaginary: self.imaginary + rhs.imaginary,
|
||||
})))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let content = "str(a + b)";
|
||||
|
||||
let ast = AstModule::parse("complex.star", content.to_owned(), &Dialect::Standard).unwrap();
|
||||
let globals = Globals::standard();
|
||||
let module = Module::new();
|
||||
// We inject some complex numbers into the module before we start.
|
||||
let a = module.heap().alloc(Complex {
|
||||
real: 1,
|
||||
imaginary: 8,
|
||||
});
|
||||
module.set("a", a);
|
||||
let b = module.heap().alloc(Complex {
|
||||
real: 4,
|
||||
imaginary: 2,
|
||||
});
|
||||
module.set("b", b);
|
||||
let mut eval = Evaluator::new(&module);
|
||||
let res = eval.eval_module(ast, &globals).unwrap();
|
||||
assert_eq!(res.unpack_str(), Some("5 + 10i"));
|
||||
*/
|
||||
}
|
Loading…
Reference in New Issue