Skip to content

Commit

Permalink
Solved TODOs
Browse files Browse the repository at this point in the history
Co-authored-by: Kelvin Steiner <me@steinerkelvin.dev>
  • Loading branch information
vkobinski and steinerkelvin committed Jul 6, 2024
1 parent 16f4601 commit 75f1f6b
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 87 deletions.
122 changes: 85 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,85 @@
Read the Docs:<br>
[FFI](https://github.com/vkobinski/benda-main/tree/master/docs/FFI.md)

This is in conceptual stage.
This is in MVP stage.

## Example

```py
from dataclasses import dataclass
from benda import bjit, u24

@dataclass
class Leaf:
value: u24 # native HVM machine integer

@dataclass
class Node:
left: 'Tree'
right: 'Tree'

Tree = Node | Leaf

# The `bjit` decorator will introspect and translate the function to HVM/Bend
# code, replacing it with a wrapper that converts the Python-level types of the
# inputs and result value, Numba-style.

@bjit
def sum_tree(tree: Tree) -> u24:
match tree:
case Leaf(value=value):
return value
case Node(left=left, right=right):
return sum_tree(left) + sum_tree(right)
case _:
raise TypeError("Invalid type for tree")

# Alternatively, you can opt to use Python big integers and other primitives,
# they will be translated to the equivalent representations automatically.

@dataclass
class Leaf2:
value: int
import benda
import random

book = benda.load_book("""
(Sort List/Nil) = List/Nil
(Sort(List/Cons head tail)) =
((Part head tail) λmin λmax
let lft=(Sort min)
let rgt=(Sort max)
(Concat lft(List/Cons head rgt)))
# Partitions a list in two halves, less-than-p and greater-than-p
(Part p List/Nil) = λt(t List/Nil List/Nil)
(Part p(List/Cons head tail)) = (Push(> head p) head(Part p tail))
# Pushes a value to the first or second list of a pair
(Push 0 x pair) = (pair λmin λmax λp(p(List/Cons x min) max))
(Push _ x pair) = (pair λmin λmax λp(p min(List/Cons x max)))
(Concat List/Nil tail) = tail
(Concat(List/Cons head tail) xs2) =
(List/Cons head(Concat tail xs2))
""")

List = book.adts.List

def gen_list(n: int, max_value: int = 0xffffff) -> list[int]:
result: list[int] = []
for _ in range(n):
result.append(random.randint(0, max_value))
return result


def to_cons_list(xs: list[int]):
result = List.Nil()

hi = len(xs)
if hi == 0:
return result

while hi > 0:
hi -= 1
result = List.Cons(xs[hi], result)

return result

def print_cons_list(list):
while True:
match list:
case List.Cons.type(value, tail):
print(value, end=", ")
list = tail
case List.Nil.type():
break


data = gen_list(5, 1000)
cons_list = to_cons_list(data)
sorted_list = book.defs.Sort(cons_list)
sorted_list = sorted_list.to_adt(book.adts.List)
print_cons_list(sorted_list)
```

## Development

Dependencies:

- Python 3.11+
- Rust
- C compiler
- maturin

### Getting dependencies with Nix (optional)

- Install Nix with [Determinate Nix Installer]

```sh
Expand All @@ -61,8 +97,20 @@ class Leaf2:

- You can run `nix develop` to enter a shell with the dependencies installed.

- You can use [`direnv`][direnv] to automatically load the environment when you
enter the project directory.
### Building

- Create and activate a Python virtual environment.
- e.g. with
```
python -m venv .venv
source .venv/bin/activate
```

- Run `make` to build the project and install the `benda` package in the virtual
environment.

<!-- - You can use [`direnv`][direnv] to automatically load the environment when you
enter the project directory. -->

[Determinate Nix Installer]: https://install.determinate.systems
[direnv]: https://direnv.net
4 changes: 4 additions & 0 deletions crates/benda/src/benda_ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use bend::diagnostics::{Diagnostics, DiagnosticsConfig};
use bend::fun::{Book, Term};
use bend::{CompileOpts, RunOpts};

/**
* TODO: move to another module
* TODO: docstring
*/
pub fn run(book: &Book) -> Option<(Term, String, Diagnostics)> {
let run_opts = RunOpts::default();
let compile_opts = CompileOpts::default().set_all();
Expand Down
30 changes: 21 additions & 9 deletions crates/benda/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fs::{remove_dir, File};
use std::io::Write;
use std::path::Path;

use num_traits::ToPrimitive;
Expand All @@ -18,21 +20,30 @@ fn switch() -> PyResult<String> {
Ok("Ok".to_string())
}

#[pyfunction]
fn load_book(py: Python, code: Py<PyString>) -> PyResult<Py<Book>> {
let mut tmp_file = File::create_new("./tmp/bend_book.tmp")
.expect("Could not create temporary file.");

let _ = tmp_file.write_all(code.to_string().as_bytes());
let _ = tmp_file.flush();

let path = Path::new("./tmp/bend_book.tmp");
let bend_book = bend::load_file_to_book(path);

let _ = std::fs::remove_file(path);

let book = Book::new(&mut bend_book.unwrap());

Ok(Py::new(py, book).unwrap())
}

#[pyfunction]
fn load_book_from_file(py: Python, path: Py<PyString>) -> PyResult<Py<Book>> {
let binding = path.to_string();
let new_path = Path::new(&binding);
let bend_book = bend::load_file_to_book(new_path);

//let code = std::fs::read_to_string(new_path)
// .map_err(|e| e.to_string())
// .unwrap();
//let bend_book = bend::fun::load_book::do_parse_book(
// &code,
// new_path,
// BendBook::default(),
//);

let book = Book::new(&mut bend_book.unwrap());

Ok(Py::new(py, book).unwrap())
Expand Down Expand Up @@ -138,6 +149,7 @@ impl PyBjit {
fn benda(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(switch, m)?)?;
m.add_function(wrap_pyfunction!(load_book_from_file, m)?)?;
m.add_function(wrap_pyfunction!(load_book, m)?)?;
m.add_class::<PyBjit>()?;
m.add_class::<U24>()?;
m.add_class::<Tree>()?;
Expand Down
3 changes: 0 additions & 3 deletions crates/benda/src/parser/builtins.rs

This file was deleted.

Loading

0 comments on commit 75f1f6b

Please sign in to comment.