mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-10-26 14:05:36 +03:00
[sc-630] Rename the crate to bend and update docs for it
This commit is contained in:
parent
02e0c3ba26
commit
cf680f559d
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -79,6 +79,25 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bend"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"TSPL 0.0.9 (git+https://github.com/developedby/TSPL.git?branch=fix-hvml-bugs)",
|
||||||
|
"clap",
|
||||||
|
"highlight_error",
|
||||||
|
"hvm-core",
|
||||||
|
"indexmap",
|
||||||
|
"insta",
|
||||||
|
"interner",
|
||||||
|
"itertools",
|
||||||
|
"loaned",
|
||||||
|
"parking_lot",
|
||||||
|
"stacker",
|
||||||
|
"stdext",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -205,25 +224,6 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hvm-lang"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"TSPL 0.0.9 (git+https://github.com/developedby/TSPL.git?branch=fix-hvml-bugs)",
|
|
||||||
"clap",
|
|
||||||
"highlight_error",
|
|
||||||
"hvm-core",
|
|
||||||
"indexmap",
|
|
||||||
"insta",
|
|
||||||
"interner",
|
|
||||||
"itertools",
|
|
||||||
"loaned",
|
|
||||||
"parking_lot",
|
|
||||||
"stacker",
|
|
||||||
"stdext",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.2.6"
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "hvm-lang"
|
name = "bend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "hvml"
|
name = "bend"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "hvml"
|
name = "bend"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
required-features = ["cli"]
|
required-features = ["cli"]
|
||||||
|
|
||||||
|
18
cspell.json
18
cspell.json
@ -19,6 +19,7 @@
|
|||||||
"Dall",
|
"Dall",
|
||||||
"datatypes",
|
"datatypes",
|
||||||
"Deque",
|
"Deque",
|
||||||
|
"destructures",
|
||||||
"desugared",
|
"desugared",
|
||||||
"desugars",
|
"desugars",
|
||||||
"dref",
|
"dref",
|
||||||
@ -29,7 +30,6 @@
|
|||||||
"hexdigit",
|
"hexdigit",
|
||||||
"hvm's",
|
"hvm's",
|
||||||
"hvmc",
|
"hvmc",
|
||||||
"hvml",
|
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"inet",
|
"inet",
|
||||||
"inets",
|
"inets",
|
||||||
@ -40,6 +40,7 @@
|
|||||||
"insta",
|
"insta",
|
||||||
"interner",
|
"interner",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"ITRS",
|
||||||
"kwargs",
|
"kwargs",
|
||||||
"lcons",
|
"lcons",
|
||||||
"linearization",
|
"linearization",
|
||||||
@ -58,10 +59,11 @@
|
|||||||
"opre",
|
"opre",
|
||||||
"oprune",
|
"oprune",
|
||||||
"oref",
|
"oref",
|
||||||
|
"parallelizable",
|
||||||
"peekable",
|
"peekable",
|
||||||
"postcondition",
|
"postcondition",
|
||||||
"prec",
|
|
||||||
"powi",
|
"powi",
|
||||||
|
"prec",
|
||||||
"readback",
|
"readback",
|
||||||
"recursively",
|
"recursively",
|
||||||
"redex",
|
"redex",
|
||||||
@ -77,6 +79,7 @@
|
|||||||
"scrutinee",
|
"scrutinee",
|
||||||
"snil",
|
"snil",
|
||||||
"stdext",
|
"stdext",
|
||||||
|
"struct",
|
||||||
"subcmd",
|
"subcmd",
|
||||||
"submatch",
|
"submatch",
|
||||||
"subpattern",
|
"subpattern",
|
||||||
@ -94,6 +97,13 @@
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
"wopts"
|
"wopts"
|
||||||
],
|
],
|
||||||
"files": ["**/*.rs", "**/*.md"],
|
"files": [
|
||||||
"ignoreRegExpList": ["HexValues", "/λ/g", "/-O/g"]
|
"**/*.rs",
|
||||||
|
"**/*.md"
|
||||||
|
],
|
||||||
|
"ignoreRegExpList": [
|
||||||
|
"HexValues",
|
||||||
|
"/λ/g",
|
||||||
|
"/-O/g"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
# Automatic vectorization with tagged lambdas
|
|
||||||
|
|
||||||
We have seen in [Dups and Sups](dups-and-sups.md) that duplications and superpositions can have labels. In HVM, lambdas and applications can have labels too.
|
|
||||||
|
|
||||||
Tagged applications will only annihilate lambdas with the same tag.
|
|
||||||
```rs
|
|
||||||
|
|
||||||
// V application's tag
|
|
||||||
#A(#A λx(body) arg)
|
|
||||||
// ^ lambda's tag
|
|
||||||
// The tag must go before the term.
|
|
||||||
// This reduces to
|
|
||||||
x = arg; body
|
|
||||||
```
|
|
||||||
|
|
||||||
For example, data types can be encoded as tagged lambdas:
|
|
||||||
|
|
||||||
```rs
|
|
||||||
// data Bool = T | F
|
|
||||||
T = #Bool λt #Bool λf t
|
|
||||||
F = #Bool λt #Bool λf f
|
|
||||||
|
|
||||||
// data List = (Cons x xs) | Nil
|
|
||||||
Cons = λx λxs #List λc #List λn #List.Cons.xs(#List.Cons.x(c x) xs)
|
|
||||||
Nil = #List λc #List λn n
|
|
||||||
```
|
|
||||||
|
|
||||||
When encoding the pattern matching, the application can then use the same label:
|
|
||||||
|
|
||||||
```rs
|
|
||||||
// not = λbool match bool { T: (F) F: (T) }
|
|
||||||
not = λbool #Bool(bool F T)
|
|
||||||
```
|
|
||||||
|
|
||||||
In fact, `match` is syntax sugar for a tagged application like the one above. This means that it is not possible to match without using tagged applications.
|
|
||||||
|
|
||||||
When an application and a lambda with different tags interact, the application "commutes" through the lambda instead of beta-reducing it. Here is how it works, roughly:
|
|
||||||
|
|
||||||
```rs
|
|
||||||
#A (#B λx (b x) a)
|
|
||||||
// Reduces to
|
|
||||||
#B λc #A((b #A λ$d c) #B(a $d))
|
|
||||||
```
|
|
||||||
|
|
||||||
This reduction can be hard to grasp, but an accurate way to understand it is that "the application goes through the lambda".
|
|
||||||
|
|
||||||
This allows, in some limited scenarios, automatic vectorization. See "limitations" for a description of the limitations.
|
|
||||||
```rs
|
|
||||||
// vectorizes to: (Cons F (Cons T (Cons F Nil)))
|
|
||||||
main = (not (Cons T (Cons F (Cons T Nil))))
|
|
||||||
```
|
|
||||||
This works because the `Bool`-tagged application in `not` passes through the `List`-tagged lambdas in `Cons` until it gets to `T` and `F`.
|
|
||||||
|
|
||||||
The tagged lambda and applications are compiled to `inet` nodes with different tag values for each data type. This allows them to commute, read [HVM-Core](https://github.com/HigherOrderCO/hvm-core/tree/main#language) to learn more about it.
|
|
||||||
|
|
||||||
### Limitations
|
|
||||||
To be able to vectorize as described here:
|
|
||||||
- The function must not be recursive
|
|
||||||
- There must not be labels in common between the function and what you want to vectorize over
|
|
@ -1,33 +1,41 @@
|
|||||||
# CLI arguments
|
# CLI arguments
|
||||||
|
|
||||||
It's possible to pass arguments to a program executed with `hvml run`:
|
It's possible to pass arguments to a program executed with `bend run` or `bend norm`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
hvml run <Path to program> [Arguments in expression form]...
|
bend run <Path to program> [Arguments in expression form]...
|
||||||
```
|
```
|
||||||
|
|
||||||
It accepts any expression that would also be valid inside an hvm-lang function.
|
It accepts any expression that would also be valid inside a bend function.
|
||||||
|
|
||||||
Arguments are passed to programs by applying them to the entrypoint function:
|
Arguments are passed to programs by applying them to the entrypoint function:
|
||||||
|
|
||||||
```js
|
```py
|
||||||
main x1 x2 x3 = (MainBody x1 x2 x3)
|
// Core syntax
|
||||||
|
main(x1, x2, x3):
|
||||||
|
MainBody(x1 x2 x3)
|
||||||
|
|
||||||
// Calling with `hvml run <file> arg1 arg2 arg3 argN`, it becomes:
|
// Calling with `bend run <file> arg1 arg2 arg3 argN`, it becomes (in core syntax):
|
||||||
|
main = (x1 λx2 λx3 (MainBody x1 x2 x3) arg1 arg2 arg3 argN)
|
||||||
main = (λx1 λx2 λx3 (MainBody x1 x2 x3) arg1 arg2 arg3 argN)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
There are no restrictions on the number of arguments passed to the program.
|
There are no restrictions on the number of arguments passed to the program.
|
||||||
|
You can even pass more arguments than the function expects, although that can lead to unexpected results.
|
||||||
```rust
|
```rust
|
||||||
// Can receive 2 CLI arguments
|
// Expects 2 CLI arguments
|
||||||
main x y = (+ x y)
|
def main(x, y):
|
||||||
|
{x - y, y - x}
|
||||||
// Can't receive CLI arguments
|
|
||||||
main = λx λy (+ x y)
|
|
||||||
|
|
||||||
// Calling with just one argument
|
// Calling with just one argument
|
||||||
hvml run <path> 5
|
bend norm <path> +5
|
||||||
λa (+ a 5)
|
λa {(- a 5) (- a +5)}
|
||||||
|
|
||||||
|
// Calling with two argument
|
||||||
|
bend norm <path> +5 +3
|
||||||
|
{+2 -2}
|
||||||
|
|
||||||
|
// Calling with three argument
|
||||||
|
// In this case, the third argument doesn't do anything due to the underlying interaction rules.
|
||||||
|
bend norm <path> +5 +3 +1
|
||||||
|
{+2 -2}
|
||||||
```
|
```
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
How are terms compiled to interaction net nodes?
|
How are terms compiled to interaction net nodes?
|
||||||
|
|
||||||
HVM-Core has a bunch of useful nodes to write IC programs.
|
HVM has a bunch of useful nodes to write IC programs.
|
||||||
Every node contains one `main` port `0` and two `auxiliary` ports, `1` and `2`.
|
Every node contains one `main` port `0` and two `auxiliary` ports, `1` and `2`.
|
||||||
|
|
||||||
There are 6 kinds of nodes, Eraser, Constructor, Reference, Number, Operation and Match.
|
There are 7 kinds of nodes, Eraser, Constructor, Duplicator, Reference, Number, Operation and Match.
|
||||||
|
|
||||||
A lambda `λx x` compiles into a Constructor node.
|
A lambda `λx x` compiles into a Constructor node.
|
||||||
An application `((λx x) (λx x))` also compiles into a Constructor node.
|
An application `((λx x) (λx x))` also compiles into a Constructor node.
|
||||||
@ -23,13 +23,10 @@ Points to the lambda variable Points to the argument
|
|||||||
When reading back, if we visit a Constructor via port 0 then we know it's a lambda, and if we visit it via port 2 it's an application.
|
When reading back, if we visit a Constructor via port 0 then we know it's a lambda, and if we visit it via port 2 it's an application.
|
||||||
|
|
||||||
- The `Number` node uses the label to store it's number.
|
- The `Number` node uses the label to store it's number.
|
||||||
- An `Op2` node uses the label to store it's operation.
|
- An `Operation` node uses the label to store it's operation.
|
||||||
- And a `Constructor` node can have a label too! This is used for `dup` and [lambda tags](automatic-vectorization-with-tagged-lambdas.md.
|
|
||||||
|
|
||||||
A duplication `dup a b = x` compiles into a Constructor node too, but with a different label.
|
A duplication `let {a b} = x` compiles into a Duplicator node.
|
||||||
A superposition `{a b}` compiles to a Constructor node too. The difference here comes from context too.
|
A superposition `{a b}` compiles to a Duplicator node too. The difference here comes from context too.
|
||||||
|
|
||||||
Additionally, nodes have labels. We use the label to store data in the node's memory, which can be used for various purposes.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
0 - Points to the sup occurrence 0 - Points to the duplicated value
|
0 - Points to the sup occurrence 0 - Points to the duplicated value
|
||||||
|
@ -120,37 +120,33 @@ Broadly speaking, a good rule of thumb in HVM is **push linear lambdas to the to
|
|||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
To show the power of fusing, here is a program that self-composes `fusing_not` 2^512 times and prints the result. `2^512` is larger than amount of atoms in the observable universe, and yet HVM is still able to work with it due to its optimal sharing capabilities.
|
To show the power of fusing, here is a program that self-composes `fusing_not` 2^24 times and prints the result.
|
||||||
|
Currently hvm is not able to handle operations between church numbers so we explicitly convert the native number to a church number in this example (which is very slow).
|
||||||
|
|
||||||
This program uses [native numbers, which are described here](native-numbers.md).
|
This program uses [native numbers, which are described here](native-numbers.md).
|
||||||
```rs
|
```rs
|
||||||
true = λt λf t
|
true = λt λf t
|
||||||
false = λt λf f
|
false = λt λf f
|
||||||
|
|
||||||
not = λboolean (boolean false true)
|
not = λboolean (boolean false true)
|
||||||
|
|
||||||
fusing_not = λboolean λt λf (boolean f t)
|
fusing_not = λboolean λt λf (boolean f t)
|
||||||
|
|
||||||
// Creates a Church numeral out of a native number
|
// Creates a Church numeral out of a native number
|
||||||
to_church n = switch n {
|
to_church n = switch n {
|
||||||
0: λf λx x
|
0: λf λx x
|
||||||
_: λf λx (f (to_church n-1 f x))
|
_: λf λx (f (to_church n-1 f x))
|
||||||
}
|
}
|
||||||
|
|
||||||
main =
|
main =
|
||||||
let two = λf λx (f (f x))
|
((to_church 0xFFFFFF) fusing_not) // try replacing this by regular not. Will it still work?
|
||||||
let two_pow_512 = ((to_church 512) two) // Composition of church-encoded numbers is equivalent to exponentiation.
|
|
||||||
// Self-composes `not` 2^512 times and prints the result.
|
|
||||||
(two_pow_512 fusing_not) // try replacing this by regular not. Will it still work?
|
|
||||||
```
|
```
|
||||||
Here is the program's output:
|
Here is the program's output:
|
||||||
```bash
|
```bash
|
||||||
$ hvml run -s fuse_magic.hvm
|
$ bend norm -s fuse_magic.hvm
|
||||||
λa λb λc (a b c)
|
Result: λa λb λc (a c b)
|
||||||
|
- ITRS: 285212661
|
||||||
RWTS : 15374
|
- TIME: 5.67s
|
||||||
- ANNI : 8193
|
- MIPS: 50.28
|
||||||
- COMM : 5116
|
|
||||||
- ERAS : 521
|
|
||||||
- DREF : 1031
|
|
||||||
- OPER : 513
|
|
||||||
TIME : 0.002 s
|
|
||||||
RPS : 9.537 m
|
|
||||||
```
|
```
|
||||||
Only 15374 rewrites! Fusing is really powerful.
|
A lot of rewrites, but most of those are just to create the church number.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use clap::{Args, CommandFactory, Parser, Subcommand};
|
use bend::{
|
||||||
use hvml::{
|
|
||||||
check_book, compile_book, desugar_book,
|
check_book, compile_book, desugar_book,
|
||||||
diagnostics::{Diagnostics, DiagnosticsConfig, Severity},
|
diagnostics::{Diagnostics, DiagnosticsConfig, Severity},
|
||||||
load_file_to_book, run_book,
|
load_file_to_book, run_book,
|
||||||
term::{Book, Name},
|
term::{Book, Name},
|
||||||
CompileOpts, OptLevel, RunOpts,
|
CompileOpts, OptLevel, RunOpts,
|
||||||
};
|
};
|
||||||
|
use clap::{Args, CommandFactory, Parser, Subcommand};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -80,8 +80,8 @@ enum Mode {
|
|||||||
#[arg(help = "Path to the input file")]
|
#[arg(help = "Path to the input file")]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|
||||||
#[arg(value_parser = |arg: &str| hvml::term::parser::TermParser::new(arg).parse_term())]
|
#[arg(value_parser = |arg: &str| bend::term::parser::TermParser::new(arg).parse_term())]
|
||||||
arguments: Option<Vec<hvml::term::Term>>,
|
arguments: Option<Vec<bend::term::Term>>,
|
||||||
},
|
},
|
||||||
/// Runs the lambda-term level desugaring passes.
|
/// Runs the lambda-term level desugaring passes.
|
||||||
Desugar {
|
Desugar {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
pub mod hvmc_to_net;
|
pub mod hvmc_to_net;
|
||||||
|
|
||||||
use crate::term::Name;
|
use crate::term::Name;
|
||||||
pub type HvmlLab = u16;
|
pub type BendLab = u16;
|
||||||
use NodeKind::*;
|
use NodeKind::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -41,13 +41,13 @@ pub enum NodeKind {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CtrKind {
|
pub enum CtrKind {
|
||||||
Con(Option<HvmlLab>),
|
Con(Option<BendLab>),
|
||||||
Tup(Option<HvmlLab>),
|
Tup(Option<BendLab>),
|
||||||
Dup(HvmlLab),
|
Dup(BendLab),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtrKind {
|
impl CtrKind {
|
||||||
pub fn to_lab(self) -> HvmlLab {
|
pub fn to_lab(self) -> BendLab {
|
||||||
#[allow(clippy::identity_op)]
|
#[allow(clippy::identity_op)]
|
||||||
match self {
|
match self {
|
||||||
CtrKind::Con(None) => 0,
|
CtrKind::Con(None) => 0,
|
||||||
|
@ -85,7 +85,7 @@ impl<'a> PyParser<'a> {
|
|||||||
} else if self.try_consume("False") {
|
} else if self.try_consume("False") {
|
||||||
return Ok(Term::Num { val: 0 });
|
return Ok(Term::Num { val: 0 });
|
||||||
}
|
}
|
||||||
Term::Var { nam: self.parse_hvml_name()? }
|
Term::Var { nam: self.parse_bend_name()? }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
@ -95,7 +95,7 @@ impl<'a> PyParser<'a> {
|
|||||||
self.consume("[")?;
|
self.consume("[")?;
|
||||||
let head = self.parse_term_py()?;
|
let head = self.parse_term_py()?;
|
||||||
if self.try_consume_keyword("for") {
|
if self.try_consume_keyword("for") {
|
||||||
let bind = self.parse_hvml_name()?;
|
let bind = self.parse_bend_name()?;
|
||||||
self.consume("in")?;
|
self.consume("in")?;
|
||||||
let iter = self.parse_term_py()?;
|
let iter = self.parse_term_py()?;
|
||||||
let mut cond = None;
|
let mut cond = None;
|
||||||
@ -116,7 +116,7 @@ impl<'a> PyParser<'a> {
|
|||||||
fn parse_term_py(&mut self) -> Result<Term, String> {
|
fn parse_term_py(&mut self) -> Result<Term, String> {
|
||||||
self.skip_trivia();
|
self.skip_trivia();
|
||||||
if self.try_consume_keyword("lambda") {
|
if self.try_consume_keyword("lambda") {
|
||||||
let names = self.list_like(|p| p.parse_hvml_name(), "", ":", ",", true, 1)?;
|
let names = self.list_like(|p| p.parse_bend_name(), "", ":", ",", true, 1)?;
|
||||||
let bod = self.parse_term_py()?;
|
let bod = self.parse_term_py()?;
|
||||||
Ok(Term::Lam { names, bod: Box::new(bod) })
|
Ok(Term::Lam { names, bod: Box::new(bod) })
|
||||||
} else {
|
} else {
|
||||||
@ -254,7 +254,7 @@ impl<'a> PyParser<'a> {
|
|||||||
if self.starts_with("(") {
|
if self.starts_with("(") {
|
||||||
self.parse_assignment_py(indent)
|
self.parse_assignment_py(indent)
|
||||||
} else {
|
} else {
|
||||||
let name = self.parse_hvml_name()?;
|
let name = self.parse_bend_name()?;
|
||||||
if self.skip_starts_with("=") {
|
if self.skip_starts_with("=") {
|
||||||
// it's actually an assignment
|
// it's actually an assignment
|
||||||
self.consume("=")?;
|
self.consume("=")?;
|
||||||
@ -316,7 +316,7 @@ impl<'a> PyParser<'a> {
|
|||||||
fn parse_as_bind(&mut self) -> Result<Option<Name>, String> {
|
fn parse_as_bind(&mut self) -> Result<Option<Name>, String> {
|
||||||
let mut bind = None;
|
let mut bind = None;
|
||||||
if self.try_consume_keyword("as") {
|
if self.try_consume_keyword("as") {
|
||||||
bind = Some(self.parse_hvml_name()?);
|
bind = Some(self.parse_bend_name()?);
|
||||||
}
|
}
|
||||||
Ok(bind)
|
Ok(bind)
|
||||||
}
|
}
|
||||||
@ -343,7 +343,7 @@ impl<'a> PyParser<'a> {
|
|||||||
if p.try_consume("_") {
|
if p.try_consume("_") {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let nam = p.parse_hvml_name()?;
|
let nam = p.parse_bend_name()?;
|
||||||
Ok(Some(nam))
|
Ok(Some(nam))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -405,7 +405,7 @@ impl<'a> PyParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fold_py(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
fn parse_fold_py(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||||
let fun = self.parse_hvml_name()?;
|
let fun = self.parse_bend_name()?;
|
||||||
let arg = self.parse_term_py()?;
|
let arg = self.parse_term_py()?;
|
||||||
let bind = self.parse_as_bind()?;
|
let bind = self.parse_as_bind()?;
|
||||||
self.consume(":")?;
|
self.consume(":")?;
|
||||||
@ -422,7 +422,7 @@ impl<'a> PyParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_do_py(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
fn parse_do_py(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||||
let fun = self.parse_hvml_name()?;
|
let fun = self.parse_bend_name()?;
|
||||||
self.consume(":")?;
|
self.consume(":")?;
|
||||||
|
|
||||||
let mut block = Vec::new();
|
let mut block = Vec::new();
|
||||||
@ -458,14 +458,14 @@ impl<'a> PyParser<'a> {
|
|||||||
|
|
||||||
fn parse_assign_pattern_py(&mut self) -> Result<AssignPattern, String> {
|
fn parse_assign_pattern_py(&mut self) -> Result<AssignPattern, String> {
|
||||||
if self.skip_starts_with("(") {
|
if self.skip_starts_with("(") {
|
||||||
let mut binds = self.list_like(|p| p.parse_hvml_name(), "(", ")", ",", true, 1)?;
|
let mut binds = self.list_like(|p| p.parse_bend_name(), "(", ")", ",", true, 1)?;
|
||||||
if binds.len() == 1 {
|
if binds.len() == 1 {
|
||||||
Ok(AssignPattern::Var(std::mem::take(&mut binds[0])))
|
Ok(AssignPattern::Var(std::mem::take(&mut binds[0])))
|
||||||
} else {
|
} else {
|
||||||
Ok(AssignPattern::Tup(binds))
|
Ok(AssignPattern::Tup(binds))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.parse_hvml_name().map(AssignPattern::Var)
|
self.parse_bend_name().map(AssignPattern::Var)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,8 +481,8 @@ impl<'a> PyParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_def_py(&mut self, indent: &mut Indent) -> Result<Definition, String> {
|
fn parse_def_py(&mut self, indent: &mut Indent) -> Result<Definition, String> {
|
||||||
let name = self.parse_hvml_name()?;
|
let name = self.parse_bend_name()?;
|
||||||
let params = self.list_like(|p| p.parse_hvml_name(), "(", ")", ",", true, 0)?;
|
let params = self.list_like(|p| p.parse_bend_name(), "(", ")", ",", true, 0)?;
|
||||||
self.consume(":")?;
|
self.consume(":")?;
|
||||||
indent.enter_level();
|
indent.enter_level();
|
||||||
let body = self.parse_stmt_py(indent)?;
|
let body = self.parse_stmt_py(indent)?;
|
||||||
@ -491,7 +491,7 @@ impl<'a> PyParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_enum_py(&mut self, indent: &mut Indent) -> Result<Enum, String> {
|
fn parse_enum_py(&mut self, indent: &mut Indent) -> Result<Enum, String> {
|
||||||
let name = self.parse_hvml_name()?;
|
let name = self.parse_bend_name()?;
|
||||||
let mut variants = Vec::new();
|
let mut variants = Vec::new();
|
||||||
self.consume(":")?;
|
self.consume(":")?;
|
||||||
indent.enter_level();
|
indent.enter_level();
|
||||||
@ -499,10 +499,10 @@ impl<'a> PyParser<'a> {
|
|||||||
if !self.skip_exact_indent(indent, true)? {
|
if !self.skip_exact_indent(indent, true)? {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let name = self.parse_hvml_name()?;
|
let name = self.parse_bend_name()?;
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
if self.skip_starts_with("(") {
|
if self.skip_starts_with("(") {
|
||||||
fields = self.list_like(|p| p.parse_hvml_name(), "(", ")", ",", true, 0)?;
|
fields = self.list_like(|p| p.parse_bend_name(), "(", ")", ",", true, 0)?;
|
||||||
}
|
}
|
||||||
variants.push((name.clone(), Variant { name, fields }));
|
variants.push((name.clone(), Variant { name, fields }));
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
use highlight_error::highlight_error;
|
use highlight_error::highlight_error;
|
||||||
use TSPL::Parser;
|
use TSPL::Parser;
|
||||||
|
|
||||||
// hvml grammar description:
|
// Bend grammar description:
|
||||||
// <Book> ::= (<Data> | <Rule>)*
|
// <Book> ::= (<Data> | <Rule>)*
|
||||||
// <Data> ::= "data" <Name> "=" ( <Name> | "(" <Name> (<Name>)* ")" )+
|
// <Data> ::= "data" <Name> "=" ( <Name> | "(" <Name> (<Name>)* ")" )+
|
||||||
// <Rule> ::= ("(" <Name> <Pattern>* ")" | <Name> <Pattern>*) "=" <Term>
|
// <Rule> ::= ("(" <Name> <Pattern>* ")" | <Name> <Pattern>*) "=" <Term>
|
||||||
@ -95,7 +95,7 @@ impl<'a> TermParser<'a> {
|
|||||||
if self.try_consume("(") {
|
if self.try_consume("(") {
|
||||||
// (name field*)
|
// (name field*)
|
||||||
let name = self.parse_top_level_name()?;
|
let name = self.parse_top_level_name()?;
|
||||||
let field_parser = |p: &mut Self| p.labelled(|p| p.parse_hvml_name(), "datatype constructor field");
|
let field_parser = |p: &mut Self| p.labelled(|p| p.parse_bend_name(), "datatype constructor field");
|
||||||
let fields = self.list_like(field_parser, "", ")", "", false, 0)?;
|
let fields = self.list_like(field_parser, "", ")", "", false, 0)?;
|
||||||
Ok((name, fields))
|
Ok((name, fields))
|
||||||
} else {
|
} else {
|
||||||
@ -194,7 +194,7 @@ impl<'a> TermParser<'a> {
|
|||||||
if self.starts_with("$") {
|
if self.starts_with("$") {
|
||||||
unexpected_tag(self)?;
|
unexpected_tag(self)?;
|
||||||
self.advance_one();
|
self.advance_one();
|
||||||
let name = self.parse_hvml_name()?;
|
let name = self.parse_bend_name()?;
|
||||||
return Ok(Pattern::Chn(name));
|
return Ok(Pattern::Chn(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ impl<'a> TermParser<'a> {
|
|||||||
if self.starts_with("$") {
|
if self.starts_with("$") {
|
||||||
self.consume("$")?;
|
self.consume("$")?;
|
||||||
unexpected_tag(self)?;
|
unexpected_tag(self)?;
|
||||||
let nam = self.parse_hvml_name()?;
|
let nam = self.parse_bend_name()?;
|
||||||
return Ok(Term::Lnk { nam });
|
return Ok(Term::Lnk { nam });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ impl<'a> TermParser<'a> {
|
|||||||
// Use
|
// Use
|
||||||
if self.try_consume_keyword("use") {
|
if self.try_consume_keyword("use") {
|
||||||
unexpected_tag(self)?;
|
unexpected_tag(self)?;
|
||||||
let nam = self.parse_hvml_name()?;
|
let nam = self.parse_bend_name()?;
|
||||||
self.consume("=")?;
|
self.consume("=")?;
|
||||||
let val = self.parse_term()?;
|
let val = self.parse_term()?;
|
||||||
self.try_consume(";");
|
self.try_consume(";");
|
||||||
@ -421,7 +421,7 @@ impl<'a> TermParser<'a> {
|
|||||||
|
|
||||||
// Var
|
// Var
|
||||||
unexpected_tag(self)?;
|
unexpected_tag(self)?;
|
||||||
let nam = self.labelled(|p| p.parse_hvml_name(), "term")?;
|
let nam = self.labelled(|p| p.parse_bend_name(), "term")?;
|
||||||
Ok(Term::Var { nam })
|
Ok(Term::Var { nam })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -443,7 +443,7 @@ impl<'a> TermParser<'a> {
|
|||||||
|
|
||||||
fn parse_top_level_name(&mut self) -> Result<Name, String> {
|
fn parse_top_level_name(&mut self) -> Result<Name, String> {
|
||||||
let ini_idx = *self.index();
|
let ini_idx = *self.index();
|
||||||
let nam = self.parse_hvml_name()?;
|
let nam = self.parse_bend_name()?;
|
||||||
let end_idx = *self.index();
|
let end_idx = *self.index();
|
||||||
if nam.contains("__") {
|
if nam.contains("__") {
|
||||||
let ctx = highlight_error(ini_idx, end_idx, self.input());
|
let ctx = highlight_error(ini_idx, end_idx, self.input());
|
||||||
@ -459,7 +459,7 @@ impl<'a> TermParser<'a> {
|
|||||||
if p.try_consume("*") {
|
if p.try_consume("*") {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let nam = p.parse_hvml_name()?;
|
let nam = p.parse_bend_name()?;
|
||||||
Ok(Some(nam))
|
Ok(Some(nam))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -477,9 +477,6 @@ impl<'a> TermParser<'a> {
|
|||||||
{
|
{
|
||||||
let ctx = highlight_error(index, index + 1, self.input);
|
let ctx = highlight_error(index, index + 1, self.input);
|
||||||
return Err(format!("Tagged terms not supported for hvm32.\n{ctx}"));
|
return Err(format!("Tagged terms not supported for hvm32.\n{ctx}"));
|
||||||
/* self.advance_one();
|
|
||||||
let nam = self.labelled(|p| p.parse_hvml_name(), "tag name")?;
|
|
||||||
Some(Tag::Named(nam)) */
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -496,13 +493,13 @@ impl<'a> TermParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_match_arg(&mut self) -> Result<(Name, Term, Vec<Name>), String> {
|
fn parse_match_arg(&mut self) -> Result<(Name, Term, Vec<Name>), String> {
|
||||||
let bnd = self.parse_hvml_name()?;
|
let bnd = self.parse_bend_name()?;
|
||||||
let arg = if self.try_consume("=") { self.parse_term()? } else { Term::Var { nam: bnd.clone() } };
|
let arg = if self.try_consume("=") { self.parse_term()? } else { Term::Var { nam: bnd.clone() } };
|
||||||
let with = if self.try_consume_keyword("with") {
|
let with = if self.try_consume_keyword("with") {
|
||||||
let mut with = vec![self.parse_hvml_name()?];
|
let mut with = vec![self.parse_bend_name()?];
|
||||||
while !self.skip_starts_with("{") {
|
while !self.skip_starts_with("{") {
|
||||||
self.try_consume(",");
|
self.try_consume(",");
|
||||||
with.push(self.parse_hvml_name()?);
|
with.push(self.parse_bend_name()?);
|
||||||
}
|
}
|
||||||
with
|
with
|
||||||
} else {
|
} else {
|
||||||
@ -755,7 +752,7 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_hvml_name(&mut self) -> Result<Name, String> {
|
fn parse_bend_name(&mut self) -> Result<Name, String> {
|
||||||
let nam = self.parse_name()?;
|
let nam = self.parse_name()?;
|
||||||
Ok(Name::new(nam))
|
Ok(Name::new(nam))
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ impl Ctx<'_> {
|
|||||||
/// ```hvm
|
/// ```hvm
|
||||||
/// main x1 x2 x3 = (MainBody x1 x2 x3)
|
/// main x1 x2 x3 = (MainBody x1 x2 x3)
|
||||||
/// ```
|
/// ```
|
||||||
/// Calling with `hvml run <file> arg1 arg2 arg3`, it becomes:
|
/// Calling with `bend run <file> arg1 arg2 arg3`, it becomes:
|
||||||
/// ```hvm
|
/// ```hvm
|
||||||
/// main = (λx1 λx2 λx3 (MainBody x1 x2 x3) arg1 arg2 arg3)
|
/// main = (λx1 λx2 λx3 (MainBody x1 x2 x3) arg1 arg2 arg3)
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -7,7 +7,7 @@ impl Book {
|
|||||||
/// Inline copies of the declared bind in the `use` expression.
|
/// Inline copies of the declared bind in the `use` expression.
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```hvml
|
/// ```bend
|
||||||
/// use id = λx x
|
/// use id = λx x
|
||||||
/// (id id id)
|
/// (id id id)
|
||||||
///
|
///
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use hvml::{
|
use bend::{
|
||||||
compile_book, desugar_book,
|
compile_book, desugar_book,
|
||||||
diagnostics::{Diagnostics, DiagnosticsConfig, Severity},
|
diagnostics::{Diagnostics, DiagnosticsConfig, Severity},
|
||||||
net::hvmc_to_net::hvmc_to_net,
|
net::hvmc_to_net::hvmc_to_net,
|
||||||
@ -107,7 +107,7 @@ fn compile_term() {
|
|||||||
|
|
||||||
term.make_var_names_unique();
|
term.make_var_names_unique();
|
||||||
term.linearize_vars();
|
term.linearize_vars();
|
||||||
let net = hvml::term::term_to_net(&term, &mut Default::default()).map_err(|e| e.to_string())?;
|
let net = bend::term::term_to_net(&term, &mut Default::default()).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
Ok(format!("{}", net))
|
Ok(format!("{}", net))
|
||||||
})
|
})
|
||||||
@ -369,7 +369,7 @@ fn cli() {
|
|||||||
let args = args_buf.lines();
|
let args = args_buf.lines();
|
||||||
|
|
||||||
let output =
|
let output =
|
||||||
std::process::Command::new(env!("CARGO_BIN_EXE_hvml")).args(args).output().expect("Run command");
|
std::process::Command::new(env!("CARGO_BIN_EXE_bend")).args(args).output().expect("Run command");
|
||||||
let res =
|
let res =
|
||||||
format!("{}{}", String::from_utf8_lossy(&output.stderr), String::from_utf8_lossy(&output.stdout));
|
format!("{}{}", String::from_utf8_lossy(&output.stderr), String::from_utf8_lossy(&output.stdout));
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -6,6 +6,6 @@ error: unexpected argument '-d' found
|
|||||||
|
|
||||||
tip: to pass '-d' as a value, use '-- -d'
|
tip: to pass '-d' as a value, use '-- -d'
|
||||||
|
|
||||||
Usage: hvml run [OPTIONS] <PATH> [ARGUMENTS]...
|
Usage: bend run [OPTIONS] <PATH> [ARGUMENTS]...
|
||||||
|
|
||||||
For more information, try '--help'.
|
For more information, try '--help'.
|
||||||
|
@ -6,6 +6,6 @@ error: unexpected argument '-d' found
|
|||||||
|
|
||||||
tip: to pass '-d' as a value, use '-- -d'
|
tip: to pass '-d' as a value, use '-- -d'
|
||||||
|
|
||||||
Usage: hvml run [OPTIONS] <PATH> [ARGUMENTS]...
|
Usage: bend run [OPTIONS] <PATH> [ARGUMENTS]...
|
||||||
|
|
||||||
For more information, try '--help'.
|
For more information, try '--help'.
|
||||||
|
Loading…
Reference in New Issue
Block a user