Skip to content

Conversation

sidprasad
Copy link

@sidprasad sidprasad commented Aug 15, 2025

This PR introduces a new variant to the ValueSkeleton data type: vs-constr-render.

vs-constr-render enables more flexible rendering of value skeletons by allowing the attachment of renderer functions to constructor-like skeletons.

@sidprasad sidprasad requested a review from jpolitz August 15, 2025 16:09
@sidprasad sidprasad changed the title [Draft] Adding VS-Constr-Render Add vs-constr-render to ValueSkeleton for Custom Rendering Aug 16, 2025
@sidprasad sidprasad marked this pull request as ready for review August 16, 2025 12:44
@jpolitz jpolitz requested a review from blerner August 19, 2025 19:12
@blerner
Copy link
Member

blerner commented Aug 19, 2025

I noticed this PR a few days ago, but I don't currently understand it (though I'm sure we discussed this design at some point, I just don't recall it right now) - is there an example of using this new construction?

@sidprasad
Copy link
Author

sidprasad commented Aug 26, 2025

@blerner

I noticed this PR a few days ago, but I don't currently understand it (though I'm sure we discussed this design at some point, I just don't recall it right now) - is there an example of using this new construction?

Thanks for checking in! There's an example of how this might hook up to CPO here: brownplt/code.pyret.org#597

I don't have a CLI-specific example, but in general the idea is to be able to say "I'm going to take control of how this value is rendered".

import valueskeleton as VS
# dom-render might be some way of rendering this in the DOM / CPO
import dom-render as DR

# Some custom rendering logic for the CLI
fun render(args):
  for raw-array-fold(str from "", elt from args, i from 0):
    str + elt + "cli"
  end
end

data RBNod:
  | Black(value, left, right)
  | Red(value, left, right)
  | Leaf(value)
 sharing:
    method _output(self):
   # Register how you'd like things to be rendered in both CLI and CPO scenarios
    VS.vs-constr-render("RBNod", [list: ], { cli: render, cpo: lam(a):  DR.genlayout( self, ...) end })
end
end

function renderValueSkeleton(val, values) {
if (thisRuntime.ffi.isVSValue(val)) { return values.pop(); } // double-check order!
else if (thisRuntime.ffi.isVSStr(val)) { return thisRuntime.unwrap(thisRuntime.getField(val, "s")); }
else if (thisRuntime.ffi.isVSConstrRender(val) && isInRendererContext(val)) {
var items = thisRuntime.ffi.toArray(thisRuntime.getField(val, "args"));
var strs = [];
Copy link
Member

Choose a reason for hiding this comment

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

These aren't actually guaranteed to be strings, though, right? (It could be arbitrary HTML or something?)

strs.push(renderValueSkeleton(items[i], values));
}
const renderers = thisRuntime.getField(val, "renderers");
return thisRuntime.getField(renderers, thisContext).app(strs);
Copy link
Member

Choose a reason for hiding this comment

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

What happens when this app returns a value that's not of the expected type? E.g. returns a DOM node when it's supposed to be a raw string? Or if it crashes/throws an error?

In general, I'm concerned about allowing arbitrary Pyret code to run during rendering, such that if the Pyret code is buggy/unexpected, the overall rendering algorithm will choke and produce no output at all, or the dreaded "error while rendering; details logged to console" message... Do you have a fallback here for what to do if that .app fails for whatever reason?

@@ -202,9 +202,24 @@ function (Namespace, jsnums, codePoint, util, exnStackParser, loader, seedrandom
*/
function isBase(obj) { return obj instanceof PBase; }

const thisContext = "cli";
Copy link
Member

Choose a reason for hiding this comment

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

This feels very brittle to me. I also don't see where this gets changed for other contexts -- you have it marked as a const, so line 221 will never look for anything other than cli context, right? (In the PR you linked to, it's a const of cpo, which again is rigid.

Also -- how does this interact with to-repr and to-string?

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.

4 participants