Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 10 additions & 10 deletions DEV.md

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ avg 2 4 9

5

Use `bpl -e 'avg←+/÷≢ ⋄ avg 2 4 9'` for a shell command. The [command-line guide](https://answerdotai.github.io/basedpl/cli.html) covers source files and pipes.
Use `bpl -e 'avg←+/÷≢ ◇ avg 2 4 9'` for a shell command. The [command-line guide](https://answerdotai.github.io/basedpl/cli.html) covers source files and pipes.

## Interactive use

In the REPL, type a backtick followed by a glyph name. For example, `` `iota `` becomes `⍳` when you press Tab or type a non-letter. Abbreviations and Alt-key shortcuts are available. `]help +` shows help for `+`. [`•prefs`](https://answerdotai.github.io/basedpl/system/prefs.html) changes display settings, such as boxes and how much of a large array shows. See [REPL](https://answerdotai.github.io/basedpl/repl.html) and the [glyph reference](https://answerdotai.github.io/basedpl/glyphs.html), which lists each glyph’s key.
In the REPL, type a backtick followed by a glyph name. For example, `` `iota `` becomes `ι` when you press Tab or type a non-letter. Abbreviations and Alt-key shortcuts are available. `]help +` shows help for `+`. [`•prefs`](https://answerdotai.github.io/basedpl/system/prefs.html) changes display settings, such as boxes and how much of a large array shows. See [REPL](https://answerdotai.github.io/basedpl/repl.html) and the [glyph reference](https://answerdotai.github.io/basedpl/glyphs.html), which lists each glyph’s key.

In Jupyter, select the installed **BasedPL** kernel. Cells share definitions and support completion, Shift-Tab help and interruption. You can also use `%%bpl` cells in a Python notebook. See [Using BPL notebooks](https://answerdotai.github.io/basedpl/notebooks.html).

Expand All @@ -55,10 +55,10 @@ Numbers separated by spaces form a vector. Arithmetic applies to every item:

11 12 13

Operators modify or combine functions. Reduce (`/`) turns addition into summation. `⍳10` generates 0…9:
Operators modify or combine functions. Reduce (`/`) turns addition into summation. `ι10` generates 0…9:

``` bpl
+/⍳10
+/ι10
```

45
Expand Down Expand Up @@ -134,14 +134,14 @@ Axes can have names, and positions along them can have string keys. Describe the

``` bpl
axes←["city":"NY" "LA";"month":"Jan" "Feb" "Mar"]
sales←axes:[10 20 30⋄40 50 60]
sales←axes:[10 20 30◇40 50 60]
"LA" "Feb"⌷sales
+/⍠"month" sales
```

50

["city":2]⍴["NY":60 "LA":150]
["city":2]ρ["NY":60 "LA":150]

Keys and names travel with axes through operations such as transpose. Arithmetic aligns matching names and keys. See [Axis keys](https://answerdotai.github.io/basedpl/keyed.html).

Expand All @@ -150,7 +150,7 @@ Keys and names travel with axes through operations such as transpose. Arithmetic
A vector of counts keeps the history: one state for each count, where count 0 is the initial value. Here, double up to four times:

``` bpl
2×⍣(⍳5) 1
2×⍣(ι5) 1
```

1 2 4 8 16
Expand Down Expand Up @@ -178,7 +178,7 @@ Explore [iteration and inverses](https://answerdotai.github.io/basedpl/glyphs/st
[Polynomials](https://answerdotai.github.io/basedpl/glyphs/quad-jot.html) support coefficients, roots and evaluation. Polynomial functions can be [differentiated](https://answerdotai.github.io/basedpl/glyphs/partial.html): for f(x) = 1 + 2x + 3x², f′(2) = 14.

``` bpl
f←[1 2 3]ₓ⌻ ⋄ f∂2ₓ
f←[1 2 3]ₓ⌻ ◇ f∂2ₓ
```

14
Expand Down
16 changes: 8 additions & 8 deletions TARGET.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use basedpl::{EvalOptions, Evaluation, Input, InterruptHandle, Output, ParseStat
use rustyline::error::ReadlineError;
use std::{io::{self, IsTerminal, Read, Write}, sync::{Arc, Mutex}};

const USAGE: &str = "Usage: bpl [-e EXPR [ARG...] | FILE [ARG...] | - [ARG...] | --worker | --costs PATH | --kernel -f CONNECTION_FILE]\n\nNo arguments: persistent BPL REPL (Ctrl-D to exit, Ctrl-C to cancel input or interrupt an evaluation).\nType `name then Tab or a non-letter to enter a symbol, e.g. `iota5 becomes ⍳5.\nUse - to execute all of stdin as one source.\n`•host \"args\"` gives the ARGs.\nUse --worker for JSON-lines requests with deadlines and interruption.\nUse --costs PATH to time a BPL speed file or directory, printing each cost and this machine's budget.\nUse --kernel -f CONNECTION_FILE to run a Jupyter kernel.\n";
const USAGE: &str = "Usage: bpl [-e EXPR [ARG...] | FILE [ARG...] | - [ARG...] | --worker | --costs PATH | --kernel -f CONNECTION_FILE]\n\nNo arguments: persistent BPL REPL (Ctrl-D to exit, Ctrl-C to cancel input or interrupt an evaluation).\nType `name then Tab or a non-letter to enter a symbol, e.g. `iota5 becomes ι5.\nUse - to execute all of stdin as one source.\n`•host \"args\"` gives the ARGs.\nUse --worker for JSON-lines requests with deadlines and interruption.\nUse --costs PATH to time a BPL speed file or directory, printing each cost and this machine's budget.\nUse --kernel -f CONNECTION_FILE to run a Jupyter kernel.\n";

/// Writes each output to stdout as the evaluation produces it. A failed write interrupts the evaluation, and `finish` then gives the write's error. Evaluations can also read standard input, when the program didn't come from it. Ctrl-C interrupts the evaluation that is running.
struct Printer { interrupt: Arc<Mutex<InterruptHandle>>, failure: Arc<Mutex<Option<io::Error>>>, input: Option<Arc<dyn Input>> }
Expand Down
2 changes: 1 addition & 1 deletion cli/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Input {
let enter = key == KeyEvent::from('\r') || key == KeyEvent::from('\n');
let tab = key == KeyEvent::from('\t');
let plain = key.1.is_empty();
let delimiter = plain && matches!(key.0, KeyCode::Char(c) if !c.is_alphabetic());
let delimiter = plain && matches!(key.0, KeyCode::Char(c) if !c.is_ascii_alphabetic());
if tab || self.active && (enter || delimiter) {
if let Some((start, prefix)) = entry(line, pos, self.aliases) {
let found = matches(prefix);
Expand Down
9 changes: 5 additions & 4 deletions cli/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ pub(crate) fn run(output: &mut impl Write) -> io::Result<()> {
let session = Session::new();
for (request, interrupt) in receive {
let id = request.as_ref().ok().and_then(|r| r["id"].as_u64());
let result = request.and_then(|r| reply(&session, &r, interrupt, output)).unwrap_or_else(|message| Reply::Json(basedpl::protocol::request_error(&message)));
let result =
request.and_then(|r| reply(&session, &r, interrupt, output)).unwrap_or_else(|message| Reply::Json(basedpl::protocol::request_error(&message)));
if let Some(id) = id { active.lock().unwrap().remove(&id); }
write_reply(output, id, result)?;
}
Expand Down Expand Up @@ -68,9 +69,9 @@ fn reply(session: &Session, request: &Value, interrupt: InterruptHandle, output:
if let Some(spec) = request.get("timing") { return basedpl_testkit::timing::request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("steps") { return basedpl_testkit::timing::steps_request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("profile") {
return basedpl_testkit::timing::profile_request(spec, &options.interrupt, ||
write_reply(output, request["id"].as_u64(), Reply::Json(serde_json::json!({"ready":true,"error":null})))
.map_err(|error| error.to_string())).map(Reply::Json);
return basedpl_testkit::timing::profile_request(spec, &options.interrupt, || {
write_reply(output, request["id"].as_u64(), Reply::Json(serde_json::json!({"ready":true,"error":null}))).map_err(|error| error.to_string())
}).map(Reply::Json);
}
if let Some(spec) = request.get("costs") { return basedpl_testkit::timing::file_request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("check") { return basedpl_testkit::reference::runner::check_file(spec, options.timeout).map(Reply::Json); }
Expand Down
16 changes: 8 additions & 8 deletions cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{io::Write, process::{Command, Stdio}};

#[test]
fn native_expression_and_diagnostic() {
for (code, expected) in [("2×3+4", "14\n"), ("⊂4ₓ ⋄ ⊂⊂4ₓ ⋄ ⊂1 2", "⊂4ₓ\n⊂⊂4ₓ\n⊂[1 2]\n"), ("f←{⍵=0?0;1+∇⍵-1} ⋄ f 500", "500\n")]
for (code, expected) in [("2×3+4", "14\n"), ("⊂4ₓ ◇ ⊂⊂4ₓ ◇ ⊂1 2", "⊂4ₓ\n⊂⊂4ₓ\n⊂[1 2]\n"), ("f←{ω=0?0;1+∇ω-1} ◇ f 500", "500\n")]
{
let output = Command::new(env!("CARGO_BIN_EXE_bpl")).args(["-e", code]).output().unwrap();
assert!(output.status.success());
Expand Down Expand Up @@ -47,13 +47,13 @@ fn worker_flushes_before_eof_and_recovers() {
});
let code = |source: &str| json!({"code": source}).to_string();
for (request, expected, error_kind, printed) in [
(code("v←⍳10"), Some(json!({"shape":[10], "data":(0..10).map(f64::from).collect::<Vec<_>>(), "prototype":0.0})), None, vec![]),
(code("v←ι10"), Some(json!({"shape":[10], "data":(0..10).map(f64::from).collect::<Vec<_>>(), "prototype":0.0})), None, vec![]),
(json!({"id":2, "code":"+/v"}).to_string(), Some(json!(45.0)), None, vec!["45"]), ("{".into(), None, Some("REQUEST"), vec![]),
(json!(3).to_string(), None, Some("REQUEST"), vec![]), (json!("1+2").to_string(), None, Some("REQUEST"), vec![]),
(json!({"id":"x", "code":"1+2"}).to_string(), None, Some("REQUEST"), vec![]), (code("⎕←7 ⋄ 1÷'a'"), None, Some("DOMAIN"), vec!["7"]),
(json!({"id":"x", "code":"1+2"}).to_string(), None, Some("REQUEST"), vec![]), (code("⎕←7 ◇ 1÷'a'"), None, Some("DOMAIN"), vec!["7"]),
(code("(2+"), None, Some("SYNTAX"), vec![]), (code("⍝ \"quoted\"\n+/v"), Some(json!(45.0)), None, vec!["45"]), (code("f←+"), None, None, vec![]),
(code("fs←[+ ×]"), None, None, vec![]), (code("+/"), None, None, vec!["+/"]), (code("f←1⊃fs ⋄ 2 f 3"), Some(json!(6.0)), None, vec!["6"]),
(code(""), None, None, vec![]), (code("⍳0"), Some(json!({"shape":[0], "data":[], "prototype":0.0})), None, vec!["⍬"]),
(code("fs←[+ ×]"), None, None, vec![]), (code("+/"), None, None, vec!["+/"]), (code("f←1⊃fs ◇ 2 f 3"), Some(json!(6.0)), None, vec!["6"]),
(code(""), None, None, vec![]), (code("ι0"), Some(json!({"shape":[0], "data":[], "prototype":0.0})), None, vec!["⍬"]),
] {
writeln!(input, "{request}").unwrap();
input.flush().unwrap();
Expand Down Expand Up @@ -83,7 +83,7 @@ fn worker_flushes_before_eof_and_recovers() {
fn batch_stdin_and_persistent_repl() {
for args in [vec!["-"], vec![]] {
let mut child = Command::new(env!("CARGO_BIN_EXE_bpl")).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap();
child.stdin.take().unwrap().write_all("v←⍳10\n+/v\n".as_bytes()).unwrap();
child.stdin.take().unwrap().write_all("v←ι10\n+/v\n".as_bytes()).unwrap();
let result = child.wait_with_output().unwrap();
assert!(result.status.success());
assert_eq!(String::from_utf8(result.stdout).unwrap(), "45\n");
Expand All @@ -99,8 +99,8 @@ fn programs_read_standard_input() {
let output = child.wait_with_output().unwrap();
(String::from_utf8(output.stdout).unwrap(), String::from_utf8(output.stderr).unwrap())
};
assert_eq!(run(&["-e", "⎕ ⋄ ⍴⎕ ⋄ ⎕ ⋄ ⍬≡⎕"], "first\n\nlast"), ("\"first\"\n[0]ₓ\n\"last\"\n$t\n".into(), String::new()));
assert_eq!(run(&["-e", "⎕ ⋄ ≢•nget \"-\""], "head\nab\ncd\n"), ("\"head\"\n6ₓ\n".into(), String::new()));
assert_eq!(run(&["-e", "⎕ ◇ ρ⎕ ◇ ⎕ ◇ ⍬≡⎕"], "first\n\nlast"), ("\"first\"\n[0]ₓ\n\"last\"\n$t\n".into(), String::new()));
assert_eq!(run(&["-e", "⎕ ◇ ≢•nget \"-\""], "head\nab\ncd\n"), ("\"head\"\n6ₓ\n".into(), String::new()));
// Standard input holds the program itself here.
for args in [&["-"][..], &[]] { assert!(run(args, "⎕\n").1.contains("IO ERROR: standard input is unavailable here")); }
}
8 changes: 4 additions & 4 deletions editors/jetbrains/BPL.tmbundle/Syntaxes/bpl.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"name": "string.quoted.single.bpl"
},
{
"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←⎕•⍺⍵⍶⍹∇⍢⍝⋄⁝\\?¯∞⍬\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿¨ᵇ⍨↣⍤∘⍠⍥↢\\.⊗⌸⍣⇄⊘@∂⍚⌺/⌿\\\\⍀⁻⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚₐᵣ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+",
"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←⎕•αω⍶⍹∇⍢⍝◇⁝\\?¯∞⍬\\+\\-×÷⌈⌊\\|\\*⊛○π√!∧∨⊼⊽\\~=≠<≤>≥ι↦:ρ≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿¨ᵇ⍨↣⍤∘⍠⍥↢\\.⊗⌸⍣⇄⊘@∂⍚⌺/⌿\\\\⍀⁻⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚₐᵣ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+",
"name": "variable.other.bpl"
},
{
Expand Down Expand Up @@ -86,7 +86,7 @@
}
},
{
"match": "[\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿]",
"match": "[\\+\\-×÷⌈⌊\\|\\*⊛○π√!∧∨⊼⊽\\~=≠<≤>≥ι↦:ρ≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿]",
"name": "support.function.bpl"
},
{
Expand All @@ -102,11 +102,11 @@
"name": "keyword.operator.dyadic.bpl"
},
{
"match": "[⍺⍵⍶⍹∇⍢]",
"match": "[αω⍶⍹∇⍢]",
"name": "variable.parameter.bpl"
},
{
"match": "[←⎕⋄⁝\\?₀₁₂₃₄₅₆₇₈₉₋]",
"match": "[←⎕◇⁝\\?₀₁₂₃₄₅₆₇₈₉₋]",
"name": "keyword.control.bpl"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"applyEndPatternLast": true
},
{
"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←是⎕出入•系⍺甲⍵乙⍶丙⍹丁∇递遞⍢循⍝注⋄句⁝隔\\?若¯负負∞永⍬空\\+加\\-减減×乘号號÷除⌈上⌊下\\|绝余絕餘\\*幂冪⍟对對○圆圓π周√根!阶拣階揀∧极且極∨析或⊼方否⊽双莫雙\\~非无無=等≠别初別<小≤限退>大≥达进達進⍳位↦至:键卸鍵⍴形≢数异數異≡同深,连連⍪接矩⊂包⊃选合選⊆巢段∊属展屬∪并独併獨∩交重⍋升⍒降↑取↓去拆⌽转轉⊖纵縱⍉翻⊤编編⊥译譯⍎行⍕文⌷索⌹解逆\\#复複↕窗⍭素⨸因⌻零值⍸处间處間⍷寻群尋⊢右⊣左¿掷抽擲¨遍ᵇ按⍨己换換↣先⍤秩∘承⍠轴軸⍥经經↢后後\\.内內⊗表⌸组組⍣次止⇄优優⊘兼@于於∂导梯導⍚择擇⌺邻鄰/总總⌿汇匯\\\\累⍀续續⁻反⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚₐᵣ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+",
"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←是⎕出入•系α甲ω乙⍶丙⍹丁∇递遞⍢循⍝注◇句⁝隔\\?若¯负負∞永⍬空\\+加\\-减減×乘号號÷除⌈上⌊下\\|绝余絕餘\\*幂冪⊛对對○圆圓π周√根!阶拣階揀∧极且極∨析或⊼方否⊽双莫雙\\~非无無=等≠别初別<小≤限退>大≥达进達進ι位↦至:键卸鍵ρ形≢数异數異≡同深,连連⍪接矩⊂包⊃选合選⊆巢段∊属展屬∪并独併獨∩交重⍋升⍒降↑取↓去拆⌽转轉⊖纵縱⍉翻⊤编編⊥译譯⍎行⍕文⌷索⌹解逆\\#复複↕窗⍭素⨸因⌻零值⍸处间處間⍷寻群尋⊢右⊣左¿掷抽擲¨遍ᵇ按⍨己换換↣先⍤秩∘承⍠轴軸⍥经經↢后後\\.内內⊗表⌸组組⍣次止⇄优優⊘兼@于於∂导梯導⍚择擇⌺邻鄰/总總⌿汇匯\\\\累⍀续續⁻反⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚₐᵣ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+",
"name": "variable.other.bpl"
},
{
Expand Down
Loading