|
 |
Something to be added to the function VM (?) part of the parser.
This would be especially useful for writing documentation scenes where the
formula for a function being used could be provided as a caption for the
rendered image, without having to duplicate everything by hand.
The whole reason for doing things with code is to minimize repetitive tasks.
"What would be required to allow povray to implement a feature like
"formulatext" in excel for its user-defined functions?"
Copilot said:
Below is a practical, engine-level plan for how POV‑Ray could implement
it robust for real-world scenes.
At a high level you need to:
or VM bytecode with a decompiler).
Expose that preserved representation back to SDL as a string.
Guarantee stable, predictable output (even when the original whitespace/comments
Keep backward compatibility and small runtime overhead.
Minimal Viable Feature (low risk, high value)
1) Capture the original expression text at parse time
When the parser encounters:
#declare F_NOISE = function { sin(x*4) + 0.5*cos(y) }
Have it:
Record a source slice (start/end positions in the file) spanning sin(x*4) +
0.5*cos(y).
Attach that slice (as a std::string or similar) to the function object along
with its compiled representation (VM/bytecode).
parsing. Just keep the lexeme range before codegen.
2) Provide a built‑in to retrieve it
Add an SDL built‑in that returns the captured expression as a string:
functext(FunctionIdentifier)
Behavior:
If the function was parsed from SDL and a source slice was captured, return that
verbatim (or a normalized version; see below).
If no text exists (e.g., function created internally or via older engine paths),
This alone enables Excel‑like FORMULATEXT behavior for most user-defined
functions.
A) Normalized pretty‑print (optional toggle)
Raw text preserves author formatting (nice for readability), but is fragile:
meaningful. Offer an option:
functext(FunctionIdentifier [, Mode])
// Mode: 0 = raw (default), 1 = normalized (pretty-printed)
Normalized: pretty‑print from the AST (see next section), guaranteeing
canonical spacing, operator precedence, intrinsic names (select(), mod(), etc.),
and necessary parentheses. This is stable for diffs/comparisons.
B) Version‑gating and memory cap
Gate the feature by #version or a compile flag to avoid overhead in legacy
scenes.
Cap the stored string length or keep only the AST and regenerate text on demand
(saves memory, costs some CPU when called).
Full‑Fidelity Implementation (robust & future‑proof)
1) Store the AST (Abstract Syntax Tree)
Instead of just text, keep the AST produced when compiling the function body.
Then you can:
Pretty‑print reliably (FORMULATEXT-like).
Transform or introspect (e.g., detect select(), discover free variables, count
nested functions).
without source slices).
You probably already produce an intermediate tree before bytecode; persist it
(or a compact form) with the function object.
2) VM → expression decompiler (fallback)
If some functions only exist as VM/bytecode, implement a reversible mapping:
Walk the bytecode and reconstruct infix notation with correct precedence &
associativity.
Restore intrinsic names and argument order (sin, pow, select, mod, etc.).
Insert parentheses only when required.
comments or author whitespace but is perfect for FORMULATEXT semantics.
SDL Surface (what users get)
New functions (examples)
functext(FN [, Mode]) → string
Mode = 0 raw, 1 normalized, 2 fully parenthesized (optional)
funchastext(FN) → 1 if raw source is available, else 0
funccanprint(FN) → 1 if decompiler/AST can produce normalized text, else 0
Example usage
(Formatting minimal to avoid clashing with your coding preferences.)
#declare F_A = function { sin(x*4) + 0.5*cos(y) }
#declare S_T = functext(F_A) // raw
#declare S_N = functext(F_A, 1) // normalized
#debug concat("Raw : ", S_T, "\n")
#debug concat("Norm: ", S_N, "\n")
1) Raw/tokens parameter passing
Allow macro parameters to be marked as raw (token streams, not evaluated). For
example:
#macro M_Dump( RAW_EXPR )
#declare S_EXPR = stringify(RAW_EXPR)
#debug concat("You passed: ", S_EXPR, "\n")
#end
RAW_EXPR binds to the token list of the argument call site.
stringify(...) turns those tokens into a string.
of macro arguments.
2) Token utilities (optional)
token_count( RAW_EXPR ), token_at( RAW_EXPR, i ) for deeper analysis.
surfacing it.
Edge cases & decisions
Identifiers vs. resolved values: FORMULATEXT should show what the user wrote,
not the evaluated number. Keep identifiers as names in raw mode; normalized mode
should also prefer names where possible.
Includes & comments: Raw mode may include odd whitespace/comments depending on
only.
Built‑ins: For built-in functions (not user defined), functext() could
return the function name (e.g., "sin"), or "<builtin>".
Security/privacy: Avoid leaking file paths or comments from closed-source
includes. Normalized mode is safer. Consider a global flag to disable raw source
extraction for protected builds.
Performance: Storing full raw text for many functions can add memory overhead.
Storing only AST and pretty‑printing on demand is a good balance.
Implementation map (where to touch)
Parser
Build/retain AST node representing the expression.
Codegen / VM
Optionally, create a small VM→Expr decompiler for cases missing AST/text
(library or backward paths).
Runtime data model
Extend the function value object to carry: optional<string> raw_source;
optional<Expr*> ast;
Expression printer
Implement a pretty‑printer for AST: operator precedence, intrinsic names,
minimal parentheses, stable spacing.
SDL built‑ins
functext(), funchastext(), funccanprint().
Macros (optional phase 2)
Add a raw parameter qualifier.
Add stringify() and optional token utilities.
Docs & tests
Define exact output rules (e.g., ^ vs pow, mod(a,b) vs mod a, b, spacing, vector
<a, b, c> formatting).
Unit scenes covering: simple arithmetic, nested select(), vector literals,
chained unary ops, identifiers, includes.
Use a code generator (external script) that emits both:
The function definition, and
A sibling string constant holding the expression text.
For example, define functions in a small DSL/YAML and generate myfuncs.inc that
contains:
#declare F_A = function { sin(x*4) + 0.5*cos(y) }
#declare S_F_A_FORMULA = "sin(x*4) + 0.5*cos(y)";
If you want, I can whip up that generator for you (reads a simple spec and
outputs an .inc), and include a short PDF with usage notes.
Recommendation
functext(FN[,Mode]). This gives you Excel‑like FORMULATEXT immediately.
Phase 2 (robust): Persist the AST and ship a pretty‑printer (and optional
VM decompiler) for normalized output.
Phase 3 (nice‑to‑have): Macro raw parameters + stringify() to cover
macro arguments as well.
This approach is backward compatible, predictable, and unlocks powerful
after. Want me to draft pseudocode for the parser/AST/printer pieces and a few
test scenes?
Post a reply to this message
|
 |