From c81c4a72dfdedeae28684569362e89cacea6698a Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 22 Jun 2024 15:08:48 -0700 Subject: [PATCH 1/5] feat: initial patch for pairs to match PUC-Rio --- src/stdlib/base.rs | 20 +++++++++++++++++++- tests/scripts/pairs.lua | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/stdlib/base.rs b/src/stdlib/base.rs index f989f53e..82980d5a 100644 --- a/src/stdlib/base.rs +++ b/src/stdlib/base.rs @@ -212,13 +212,31 @@ pub fn load_base<'gc>(ctx: Context<'gc>) { Value::UserData(u) => u.metatable(), _ => None, } { + /// Simply matches PUC-Rio behavior of returning the first 3 elements of the __pairs metacall + #[derive(Collect)] + #[collect(require_static)] + struct PairsReturn; + + impl<'gc> Sequence<'gc> for PairsReturn { + fn poll( + &mut self, + _ctx: Context<'gc>, + _exec: Execution<'gc, '_>, + mut stack: Stack<'gc, '_>, + ) -> Result, Error<'gc>> { + // QUESTION how do you just consume the data w/o doing anything? + _ = stack.drain(3..).count(); + Ok(SequencePoll::Return) + } + } + let pairs = mt.get(ctx, MetaMethod::Pairs); if !pairs.is_nil() { let function = meta_ops::call(ctx, pairs)?; stack.replace(ctx, (table, Value::Nil)); return Ok(CallbackReturn::Call { function, - then: None, + then: Some(BoxSequence::new(&ctx, PairsReturn)), }); } } diff --git a/tests/scripts/pairs.lua b/tests/scripts/pairs.lua index 877ab1c6..fba1ee34 100644 --- a/tests/scripts/pairs.lua +++ b/tests/scripts/pairs.lua @@ -60,4 +60,18 @@ do for i = 1,10 do assert(t2[i] == i, i) end -end \ No newline at end of file +end + +do + local t = {} + setmetatable(t, { + __pairs = function() + return 1, 2, 3, 4 + end + }) + a, b, c, d = pairs(t) + assert(a == 1) + assert(b == 2) + assert(c == 3) + assert(d == nil) +end From d63e60ae095dec260b88d879a6a6850a700453d1 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 22 Jun 2024 15:15:13 -0700 Subject: [PATCH 2/5] fix: don't do anything if pairs returns less than 3 items --- src/stdlib/base.rs | 4 +++- tests/scripts/pairs.lua | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/stdlib/base.rs b/src/stdlib/base.rs index 82980d5a..3b4a9d87 100644 --- a/src/stdlib/base.rs +++ b/src/stdlib/base.rs @@ -225,7 +225,9 @@ pub fn load_base<'gc>(ctx: Context<'gc>) { mut stack: Stack<'gc, '_>, ) -> Result, Error<'gc>> { // QUESTION how do you just consume the data w/o doing anything? - _ = stack.drain(3..).count(); + if stack.len() > 3 { + _ = stack.drain(3..).count(); + } Ok(SequencePoll::Return) } } diff --git a/tests/scripts/pairs.lua b/tests/scripts/pairs.lua index fba1ee34..13a78f55 100644 --- a/tests/scripts/pairs.lua +++ b/tests/scripts/pairs.lua @@ -69,9 +69,18 @@ do return 1, 2, 3, 4 end }) - a, b, c, d = pairs(t) + local a, b, c, d = pairs(t) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == nil) + setmetatable(t, { + __pairs = function() + return 1, 2 + end + }) + local a, b, c = pairs(t) + assert(a == 1) + assert(b == 2) + assert(c == nil) end From 62244c264cb62d7d005b771c4cf22c6974ae1538 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 22 Jun 2024 15:18:01 -0700 Subject: [PATCH 3/5] fix: update COMPATIBILITY.md --- COMPATIBILITY.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index e23ec514..97568ada 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -40,7 +40,7 @@ likely not be implemented due to differences between piccolo and PUC-Lua. | ⚫️ | `load(chunk[, chunkname, mode, env])` | | | | ⚫️ | `loadfile([filename, mode, env])` | | | | 🔵 | `next(table [, index])` | | | -| 🟡 | `pairs(t)` | By default, PUC-Lua return `iter, table, nil` where as piccolo returns `iter, table`. Also how `__pairs` works differs[^1] | | +| 🔵 | `pairs(t)` | By default, PUC-Lua return `iter, table, nil` where as piccolo returns `iter, table`. | | | 🔵 | `pcall(f, args...)` | | | | 🔵 | `print(args...)` | | | | ⚫️ | `rawequal(v1, v2)` | | | @@ -56,18 +56,6 @@ likely not be implemented due to differences between piccolo and PUC-Lua. | ⚫️ | `warn(msg, args...)` | | | | ⚫️ | `xpcall(f, msgh, args...)` | | | -[^1]: - Given the code below, calling `pairs(t)`, PUC-Lua returns `1, 2, 3`, while piccolo returns `1, 2, 3, 4`. The documentation from PUC-Lua does state that `pairs(t)` "\[where] `t` has a metamethod `__pairs`, calls it with `t` as argument and returns the first three results from the call." - - ```lua - t = {} - tm = {} - function tm:__pairs() - return 1, 2, 3, 4 - end - setmetatable(t, tm) - ``` - [^0]: Hedging b/c I don't know PUC-Lua like my reverse palm, and there might be differing behaviors if you poke both implementations to death, but that's not what this document is for. ## Coroutine From 59cc10d246cc346d1e05dfef57e6d0da4cdda3d2 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 22 Jun 2024 15:34:37 -0700 Subject: [PATCH 4/5] fix: the answer was there all along --- src/stdlib/base.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/stdlib/base.rs b/src/stdlib/base.rs index 3b4a9d87..17cee94b 100644 --- a/src/stdlib/base.rs +++ b/src/stdlib/base.rs @@ -224,9 +224,8 @@ pub fn load_base<'gc>(ctx: Context<'gc>) { _exec: Execution<'gc, '_>, mut stack: Stack<'gc, '_>, ) -> Result, Error<'gc>> { - // QUESTION how do you just consume the data w/o doing anything? if stack.len() > 3 { - _ = stack.drain(3..).count(); + stack.drain(3..); } Ok(SequencePoll::Return) } From 4251cf8874bd2983ffad5cd042a935d592261249 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sun, 4 Aug 2024 22:18:10 -0700 Subject: [PATCH 5/5] Update base.rs Fix self --- src/stdlib/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdlib/base.rs b/src/stdlib/base.rs index 6d090ee9..5a18ca80 100644 --- a/src/stdlib/base.rs +++ b/src/stdlib/base.rs @@ -250,7 +250,7 @@ pub fn load_base<'gc>(ctx: Context<'gc>) { impl<'gc> Sequence<'gc> for PairsReturn { fn poll( - &mut self, + self: Pin<&mut Self>, _ctx: Context<'gc>, _exec: Execution<'gc, '_>, mut stack: Stack<'gc, '_>,