Skip to content

Migrate binary_tree module to Conductor#790

Open
Akshay-2007-1 wants to merge 9 commits into
conductor-migrationfrom
feat/migrate-binary-tree
Open

Migrate binary_tree module to Conductor#790
Akshay-2007-1 wants to merge 9 commits into
conductor-migrationfrom
feat/migrate-binary-tree

Conversation

@Akshay-2007-1

@Akshay-2007-1 Akshay-2007-1 commented Jul 11, 2026

Copy link
Copy Markdown

Description

Fixes #768

Migrates the binary_tree module to be Conductor-ready, following the pattern established by the repeat module (#698). binary_tree has no tab/visualization component, so this is scoped entirely to src/bundles/binary_tree/.

  • functions.ts is rewritten against Conductor's IDataHandler (pair_make/pair_head/pair_tail) instead of js-slang's stdlib/list, so tree structure is built from real Conductor Pairs rather than native JS arrays.
  • index.ts is now a BaseModulePlugin subclass with each exported function as a @moduleMethod-decorated closure, mirroring repeat.
  • The stored tree entry value is declared DataType.OPAQUE at the module boundary (arbitrary Source/Python values aren't representable as a single concrete DataType).
  • is_tree/is_empty_tree declare no argument type, since they're predicates that must accept a value of any type and answer false rather than throw — a declared type would mean the FFI boundary type-asserts and throws before the predicate body ever runs.
  • tsconfig.json picked up the same experimentalDecorators/emitDecoratorMetadata overrides repeat already has (this bundle was missing them, which breaks the moduleMethod decorator under TS's native Stage-3 decorators).

Testing

  • yarn workspace @sourceacademy/bundle-binary_tree run tsc — passes
  • yarn workspace @sourceacademy/bundle-binary_tree run lint — passes
  • yarn workspace @sourceacademy/bundle-binary_tree run test — 16/16 passing, against @sourceacademy/modules-testplugin's TestDataHandler
  • yarn workspace @sourceacademy/bundle-binary_tree run build — produces build/bundles/binary_tree.js
  • End-to-end: loaded the built bundle into py-slang's PyCseEvaluator (via py-slang#217's module loader work) and drove make_tree/entry/left_branch/right_branch/is_tree from real Python-shaped values through the actual pythonToModule/moduleToPython conversion code — all round-trip correctly.

Notes for reviewers

Getting the end-to-end test working surfaced two bugs upstream of this PR, not fixable within binary_tree itself:

  • BaseModulePlugin.initialise() in conductor registers each exported method as a detached function reference (this[name]) without binding it to the instance, so this is undefined inside any exported method body once a real evaluator calls it. This breaks every Conductor module that uses ordinary class methods (i.e. all of them), not just this one. Filing a fix against conductor separately.
  • moduleToPython/pythonToModule in py-slang#217 flatten a returned DataType.PAIR into a Python list and convert Python lists back to DataType.ARRAY, which loses identity for any function returning a Pair that's meant to be passed back into another module call (e.g. left_branch(t)). Flagging this on that PR directly since the affected file is new there.

Rewrites the binary_tree bundle as a Conductor BaseModulePlugin, backed
by IDataHandler pair/list primitives instead of js-slang's stdlib. Tree
entries are stored as OPAQUE values at the module boundary; is_tree and
is_empty_tree declare no arg type so they can accept any DataType and
answer false rather than throw, matching their predicate semantics.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request migrates the binary_tree bundle from js-slang to @sourceacademy/conductor, refactoring the tree operations, types, and tests to utilize Conductor's IDataHandler and TypedValue system, and exporting the module via a new BinaryTreeModulePlugin class. The review feedback suggests enhancing robustness by adding null/undefined checks for the value parameter in is_tree, is_empty_tree, and assertNonEmptyTree to prevent runtime crashes. Additionally, it is recommended to throw EvaluatorRuntimeError instead of generic Error objects for arity mismatches in the module plugin methods.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/bundles/binary_tree/src/functions.ts
Comment thread src/bundles/binary_tree/src/functions.ts
Comment thread src/bundles/binary_tree/src/functions.ts
Comment thread src/bundles/binary_tree/src/index.ts Outdated
Comment thread src/bundles/binary_tree/src/index.ts
Comment thread src/bundles/binary_tree/src/index.ts
@Akshay-2007-1 Akshay-2007-1 self-assigned this Jul 11, 2026
@Akshay-2007-1
Akshay-2007-1 marked this pull request as draft July 11, 2026 12:11
is_tree/is_empty_tree/assertNonEmptyTree now guard against a
missing/undefined value instead of crashing with a raw TypeError, and
the plugin's arity-check throws now use EvaluatorRuntimeError (already
used elsewhere in this module) instead of a generic Error.

Also adds the same __bindExportedMethods() workaround repeat/rune use
for the unbound-method issue in BaseModulePlugin.initialise()
(conductor#41), since this fix isn't merged upstream yet.
@Akshay-2007-1
Akshay-2007-1 marked this pull request as ready for review July 11, 2026 14:09
@Akshay-2007-1

Copy link
Copy Markdown
Author

@coderabbitai, any review comments?

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

@Akshay-2007-1 Sure thing — I'll kick off a full review of the changes in this PR now. You'll see my review comments shortly, covering functions.ts, index.ts, and the tsconfig.json update in src/bundles/binary_tree/.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0331d85f-4198-4185-99f3-31065bad8d16

📥 Commits

Reviewing files that changed from the base of the PR and between 7c75a40 and 2a97432.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • src/bundles/binary_tree/package.json
  • src/bundles/binary_tree/src/__tests__/index.test.ts
  • src/bundles/binary_tree/src/functions.ts
  • src/bundles/binary_tree/src/index.ts
  • src/bundles/binary_tree/src/types.ts
  • src/bundles/binary_tree/tsconfig.json

Walkthrough

The binary tree module is migrated from synchronous native structures to Conductor TypedValue representations. Operations now use asynchronous evaluator calls, exports are provided through BinaryTreeModulePlugin, and tests use typed handler-generated fixtures.

Changes

Binary Tree Conductor Migration

Layer / File(s) Summary
Typed tree representation
src/bundles/binary_tree/src/types.ts, src/bundles/binary_tree/src/functions.ts
Tree aliases and empty-tree construction now use Conductor typed values.
Evaluator-based tree operations
src/bundles/binary_tree/src/functions.ts
Construction, validation, error handling, and branch access use asynchronous evaluator operations.
Conductor module plugin surface
src/bundles/binary_tree/src/index.ts, src/bundles/binary_tree/tsconfig.json, src/bundles/binary_tree/package.json
The module now exposes decorated, evaluator-aware plugin methods with updated compilation and development settings.
Typed async test coverage
src/bundles/binary_tree/src/__tests__/index.test.ts
Tests build typed trees and validate asynchronous predicates, accessors, errors, and opaque values.

Estimated code review effort: 4 (Complex) | ~45 minutes

Poem

I’m a rabbit with a typed tree to tend,
Pair by pair, where branches bend.
Async carrots hop through the stream,
Opaque numbers join the dream.
The plugin blooms—what a leafy scheme!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migrating the binary_tree module to Conductor.
Description check ✅ Passed It covers the issue fixed, change summary, motivation/context, and testing; only the checklist template section is missing.
Linked Issues check ✅ Passed The PR implements the requested Conductor migration for binary_tree in #768.
Out of Scope Changes check ✅ Passed No clear out-of-scope changes are evident; the package, tests, and tsconfig updates support the Conductor migration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/migrate-binary-tree

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

master's binary_tree gained this validation while conductor-migration
was diverging (make_tree(0, 0, null) previously constructed a
malformed tree silently instead of throwing). Ports the same check,
using EvaluatorTypeError to match this module's existing Conductor
error style rather than modules-lib's InvalidParameterTypeError, which
doesn't apply here since this module no longer goes through js-slang.

@AaravMalani AaravMalani left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, LGTM. The only thing left is documentation, but since that's still pending as per #765, I'm approving it in advance

Comment thread src/bundles/binary_tree/src/functions.ts
Comment thread src/bundles/binary_tree/src/index.ts Outdated
return await make_tree_func(this.evaluator, value, left, right);
}

// No declared arg type: is_tree is a predicate that must accept a value of any

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, for this I think we should add a DataType.ANY which just accepts all values. Thoughts @Akshay-2007-1 @martin-henz?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that'd be cleaner than the current "just don't declare a type" convention for predicates like is_tree. It touches Conductor itself though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, is_tree should take ANY argument.

The upstream binding fix (source-academy/conductor#41) is merged and
published, making the per-module bind workaround unnecessary. Also drops the
constructor override, which was left as a pure passthrough to the base class
once the workaround was removed.
repeat and testplugin depended on conductor via a bare, unpinned GitHub URL.
yarn.lock had resolved and locked that to a commit from before even the
BaseModulePlugin binding fix (conductor#41) - a real `yarn install` builds
against that stale, broken conductor entirely silently, since nothing
forces Yarn to re-resolve an already-locked git dependency. Other bundles
(rune, etc.) already depend on the versioned npm release; switched these
two to match (^0.7.0), which also resolves a duplicate-package TS error
that showed up in any bundle depending on both specs simultaneously.
Was depending on conductor via a bare, unpinned GitHub URL, which yarn.lock
had resolved and locked to a commit from before the BaseModulePlugin binding
fix (conductor#41). Switched to the versioned npm range other bundles
already use (^0.7.0), matching the same fix applied to midi.
@Akshay-2007-1

Akshay-2007-1 commented Jul 15, 2026

Copy link
Copy Markdown
Author

LGTM except documentation

Check this

…igrate-binary-tree

# Conflicts:
#	src/bundles/binary_tree/package.json
#	src/bundles/binary_tree/src/__tests__/index.test.ts
#	src/bundles/binary_tree/src/functions.ts
#	yarn.lock
… stricter tsconfig

Picked up as part of merging conductor-migration in - noImplicitOverride is
now enabled repo-wide, and exportedNames/channelAttach shadow members
declared on BaseModulePlugin.
@Akshay-2007-1

Copy link
Copy Markdown
Author

Re: the `is_tree`/`DataType.ANY` discussion above - opened source-academy/conductor#44, which adds `DataType.ANY` (a value of any type, expanding to the union of all concrete `TypedValue`s at the type level - same trick as `DataType.LIST` already does for `PAIR | EMPTY_LIST`) along with the supporting changes to `isSameType`/`isReferenceType`/`ExternTypeOf` so it doesn't fall through unhandled.

Not wiring it into `is_tree`/`is_empty_tree` here yet since it depends on an unreleased conductor version - once #44 merges and a new version is published, updating this PR (or a quick follow-up) to declare `[DataType.ANY]` instead of the current `[]`/no-declared-type convention should be a small change.

martin-henz pushed a commit to source-academy/conductor that referenced this pull request Jul 16, 2026
* Add DataType.ANY for predicate-style module method arguments

Modules like binary_tree's is_tree need a predicate that accepts a
value of any DataType and answers based on its shape, rather than
throwing on a mismatched type - previously the only way to express
this was to omit the argument's declared type entirely from a
moduleMethod's signature. DataType.ANY makes this an explicit,
self-documenting choice instead.

TypedValue<DataType.ANY> expands to the union of all concrete
TypedValues (mirroring the existing LIST -> PAIR|EMPTY_LIST
special-case), and isSameType/isReferenceType/ExternTypeOf are
updated so ANY doesn't fall through their lookups unhandled.

Addresses Martin Henz and Aarav Malani's discussion on
source-academy/modules#790 (review comment on is_tree's signature).

* Check t1 === t2 before DataType.ANY in isSameType

Per Gemini review on PR #44: identical types are the common case, so
checking equality first avoids two extra ANY comparisons on that path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants