From a8d9c3dfba2dd6f78465fa001551d71b6c850281 Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:46:39 +0530 Subject: [PATCH 1/6] Represent Tell method sentences as no-echo call statements --- native/internal/tell/parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/internal/tell/parser.go b/native/internal/tell/parser.go index a867efe..1bb5630 100644 --- a/native/internal/tell/parser.go +++ b/native/internal/tell/parser.go @@ -563,7 +563,7 @@ func parseSimpleStatement(source string, line, column int) *simpleStatement { } if valid { callee := memberExpression{value: nameExpression{name: target}, member: method} - return &simpleStatement{kind: "expression", source: source, expression: callExpression{callee: callee, args: arguments}, hasExpression: true} + return &simpleStatement{kind: "call", source: source, expression: callExpression{callee: callee, args: arguments}, hasExpression: true} } } } From fa9677104fce1c7da4c274f1c597996d864749ca Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:46:44 +0530 Subject: [PATCH 2/6] Represent Tell method sentences as no-echo call statements --- tell/interpreter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tell/interpreter.py b/tell/interpreter.py index e5c8092..c66b482 100644 --- a/tell/interpreter.py +++ b/tell/interpreter.py @@ -919,7 +919,7 @@ def parsed_expression(expression: str) -> TellExpr | None: if method: callee = TellExpr("member", method, (TellExpr("name", parts[0]),)) return { - "kind": "expression", + "kind": "call", "source": text, "expression": TellExpr("call", children=(callee, *arguments), names=(None,) * len(arguments)), } From 34cdddf485d993382c1772c677aa7dc8fdd4f6bc Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:48:20 +0530 Subject: [PATCH 3/6] Test Tell method sentences are no-echo call statements --- native/internal/tell/tell_test.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/native/internal/tell/tell_test.go b/native/internal/tell/tell_test.go index 71c2f83..94dfca9 100644 --- a/native/internal/tell/tell_test.go +++ b/native/internal/tell/tell_test.go @@ -113,11 +113,32 @@ func TestParserBuildsExpressionASTsForCommonStatements(t *testing.T) { t.Fatalf("natural object construction did not produce a parsed statement: %#v, %v", constructed, err) } told, err := parse("Tell box to open with \"wide\".", "ast.tell") - if err != nil || told[0].simple == nil || told[0].simple.kind != "expression" { + if err != nil || told[0].simple == nil || told[0].simple.kind != "call" { t.Fatalf("Tell method sentence did not produce an expression AST: %#v, %v", told, err) } } +func TestTellMethodSentenceDiscardsReturnValue(t *testing.T) { + source := `Create a class called Counter: + When creating a Counter: + Remember 41 as this.value. + End constructor. + To get_value: + Give back this.value. + End function. +End class. +Let counter be a new Counter. +Tell counter to get_value. +Say "done".` + var output bytes.Buffer + if err := RunWithIO(source, "tell-call.tell", bytes.NewReader(nil), &output); err != nil { + t.Fatal(err) + } + if got, want := output.String(), "done\n"; got != want { + t.Fatalf("Tell method sentence output = %q, want %q (method return must not echo)", got, want) + } +} + func TestMultipleAssignmentValidatesBeforeMutating(t *testing.T) { runtime := newRuntime("test.tell", nil, &bytes.Buffer{}, DefaultExecutionLimits()) runtime.global.set("first", float64(1)) From 0a09d201627cc73ee4d165db33886164806796a2 Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:48:25 +0530 Subject: [PATCH 4/6] Test Python Tell method sentences do not echo results --- tests/test_tell.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_tell.py b/tests/test_tell.py index d25b7aa..0c33020 100644 --- a/tests/test_tell.py +++ b/tests/test_tell.py @@ -21,6 +21,7 @@ def test_parser_builds_expression_asts_for_common_statements(self): constructed = Parser("Let box be a new Box.").parse()[0] self.assertEqual(constructed.data["simple"]["expression"].kind, "call") told = Parser('Tell box to open with "wide".').parse()[0] + self.assertEqual(told.data["simple"]["kind"], "call") self.assertEqual(told.data["simple"]["expression"].kind, "call") member_assignment = Parser('Set box.name to "Ada".').parse()[0] self.assertEqual(member_assignment.data["simple"]["kind"], "set_member") @@ -36,6 +37,23 @@ def run_tell(self, source, answers=None): interpreter.run(source, "test.tell") return output, interpreter.global_env + def test_tell_method_sentence_discards_return_value(self): + source = """ +Create a class called Counter: + When creating a Counter: + Remember 41 as this.value. + End constructor. + To get_value: + Give back this.value. + End function. +End class. +Let counter be a new Counter. +Tell counter to get_value. +Say "done". +""" + output, _ = self.run_tell(source) + self.assertEqual(output, ["done"]) + def test_variables_math_and_interpolation(self): output, env = self.run_tell(''' Let name be "Ada". From 28edf182aa4718c1f70227023ba9e38af5ae633d Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:48:30 +0530 Subject: [PATCH 5/6] Test compiled Tell method sentences discard return values --- native/internal/tell/bytecode_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/native/internal/tell/bytecode_test.go b/native/internal/tell/bytecode_test.go index a2e3018..9dd4f42 100644 --- a/native/internal/tell/bytecode_test.go +++ b/native/internal/tell/bytecode_test.go @@ -53,6 +53,23 @@ Say person.name.` } } +func TestBytecodeTellMethodSentenceDiscardsReturnValue(t *testing.T) { + source := `Create a class called Counter: + When creating a Counter: + Remember 41 as this.value. + End constructor. + To get_value: + Give back this.value. + End function. +End class. +Let counter be a new Counter. +Tell counter to get_value. +Say "done".` + if got, want := runCompiled(t, source), "done\n"; got != want { + t.Fatalf("compiled Tell method sentence output = %q, want %q", got, want) + } +} + func TestBytecodeSupportsTupleValues(t *testing.T) { source := `Let first, second be (1, 2). Let values be (first, second, 3). From 76f9534a1d130e2bc1656f5cf3669c7ec1481195 Mon Sep 17 00:00:00 2001 From: KernelGhost-gif Date: Thu, 12 Nov 2026 20:48:58 +0530 Subject: [PATCH 6/6] Add cross-runtime conformance for no-echo Tell method calls --- conformance/core.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conformance/core.json b/conformance/core.json index 138d4de..09c0e72 100644 --- a/conformance/core.json +++ b/conformance/core.json @@ -299,5 +299,10 @@ "name": "typed Call and Run statements", "source": "To combine with left and right:\n Say left plus right.\nEnd function.\nCall combine with 2 and 3.\nRun combine with 4 and 1.", "output": "5\n5\n" + }, + { + "name": "Tell method call discards return value", + "source": "Create a class called Counter:\n When creating a Counter:\n Remember 41 as this.value.\n End constructor.\n To get_value:\n Give back this.value.\n End function.\nEnd class.\nLet counter be a new Counter.\nTell counter to get_value.\nSay \"done\".", + "output": "done\n" } ]