diff --git a/changelog.md b/changelog.md index b3edb2e0..a1a24545 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ This version is not yet released. If you are reading this on the website, then t - Add the experimental [`fft`](https://uiua.org/docs/fft) function, which performs the Fast Fourier transform - The inverse FFT is also supported via [`un °`](https://uiua.org/docs/un) - Add the experimental [`astar`](https://uiua.org/docs/astar) modifier, which performs the A* pathfinding algorithm +- Add the experimental [`with ⫯`](https://uiua.org/docs/with) modifier, which is a complement to [`on ⟜`](https://uiua.org/docs/on) and [`by ⊸`](https://uiua.org/docs/by) - Adjacent [`trace ⸮`](https://uiua.org/docs/trace)s now function as a single [`trace ⸮`](https://uiua.org/docs/trace) of more values - N+1 adjacent [`stack ?`](https://uiua.org/docs/stack)s now format to N [`trace ⸮`](https://uiua.org/docs/trace)s - Add the [`&camcap`](https://uiua.org/docs/&camcap) system function, which captures a frame from a camera diff --git a/site/primitives.json b/site/primitives.json index fdec1db5..4f47c591 100644 --- a/site/primitives.json +++ b/site/primitives.json @@ -1248,6 +1248,14 @@ "class": "DyadicArray", "description": "The n-wise windows of an array" }, + "with": { + "glyph": "⫯", + "outputs": 1, + "modifier_args": 1, + "class": "Stack", + "description": "Call a function but keep its last argument on the top of the stack", + "experimental": true + }, "xlsx": { "args": 1, "outputs": 1, diff --git a/site/styles.css b/site/styles.css index 2e615d72..0b77c242 100644 --- a/site/styles.css +++ b/site/styles.css @@ -740,7 +740,7 @@ input[type=number] { .glyph-button { font-family: "Code Font", monospace; - font-size: 0.90em; + font-size: 0.89em; padding: 0.05em; margin: 0em; background-color: transparent; diff --git a/src/compile/modifier.rs b/src/compile/modifier.rs index dc6a7869..1181a68d 100644 --- a/src/compile/modifier.rs +++ b/src/compile/modifier.rs @@ -447,7 +447,7 @@ impl Compiler { }}; } match prim { - Dip | Gap | On | By => { + Dip | Gap | On | By | With => { // Compile operands let (mut instrs, sig) = self.compile_operand_word(modified.operands[0].clone())?; // Dip (|1 …) . diagnostic @@ -488,7 +488,7 @@ impl Compiler { instrs.insert(0, Instr::Prim(Pop, span)); Signature::new(sig.args + 1, sig.outputs) } - On => { + prim if prim == On || prim == With && sig.args <= 1 => { instrs.insert( 0, if sig.args == 0 { @@ -543,12 +543,53 @@ impl Compiler { } Signature::new(sig.args.max(1), sig.outputs + 1) } + With => { + let mut i = 0; + if sig.args > 1 { + instrs.insert( + i, + Instr::PushTemp { + stack: TempStack::Inline, + count: sig.args - 1, + span, + }, + ); + i += 1; + } + instrs.insert(i, Instr::Prim(Dup, span)); + i += 1; + if sig.args > 1 { + instrs.insert( + i, + Instr::PopTemp { + stack: TempStack::Inline, + count: sig.args - 1, + span, + }, + ); + } + if sig.outputs > 2 { + instrs.push(Instr::PushTemp { + stack: TempStack::Inline, + count: sig.outputs - 2, + span, + }); + for _ in 0..sig.outputs - 2 { + instrs.push(Instr::Prim(Flip, span)); + instrs.push(Instr::PopTemp { + stack: TempStack::Inline, + count: 1, + span, + }); + } + } + instrs.push(Instr::Prim(Flip, span)); + Signature::new(sig.args.max(1), sig.outputs + 1) + } _ => unreachable!(), }; if call { - // self.push_instr(Instr::PushSig(sig)); self.push_all_instrs(instrs); - // self.push_instr(Instr::PopSig); } else { let func = self.make_function(modified.modifier.span.clone().into(), sig, instrs); diff --git a/src/primitive/defs.rs b/src/primitive/defs.rs index 0e80b5c4..bdecd0de 100644 --- a/src/primitive/defs.rs +++ b/src/primitive/defs.rs @@ -1679,6 +1679,17 @@ primitive!( /// : ⊜□⊸≠ @ "Hey there buddy" /// : ⊕□⊸◿ 5 [2 9 5 21 10 17 3 35] ([1], By, Stack, ("by", '⊸')), + /// Call a function but keep its last argument on the top of the stack + /// + /// ex: # Experimental! + /// : [⫯+ 2 5] + /// : [⫯- 2 5] + /// + /// [with] can be used to copy a value from deep in the stack, or to move it. + /// ex: # Experimental! + /// : [⫯⊙⊙⊙∘ 1 2 3 4] + /// : [⫯⊙⊙⊙◌ 1 2 3 4] + ([1], With, Stack, ("with", '⫯')), /// Call a function on two sets of values /// /// For monadic functions, [both] calls its function on each of the top 2 values on the stack. diff --git a/src/primitive/mod.rs b/src/primitive/mod.rs index 7c3e7e33..d4ca18c2 100644 --- a/src/primitive/mod.rs +++ b/src/primitive/mod.rs @@ -386,7 +386,7 @@ impl Primitive { use SysOp::*; matches!( self, - (Coordinate | Astar | Fft | Triangle | Case) + With | (Coordinate | Astar | Fft | Triangle | Case) | Sys(Ffi | MemCopy | MemFree | TlsListen) | (Stringify | Quote | Sig) ) @@ -834,6 +834,7 @@ impl Primitive { | Primitive::Dip | Primitive::On | Primitive::By + | Primitive::With | Primitive::Gap | Primitive::Un | Primitive::Under