R icon indicating copy to clipboard operation
R copied to clipboard

Fall cleaning pass ideas :fallen_leaf: :broom:

Open dgkf opened this issue 1 year ago • 2 comments

Just documenting a few cleanup ideas to give an opportunity for input before I embark on a few cleanup passes:

  • [x] Convert lazy_static! to OnceCell
  • [x] Improve how formal arguments are defined, planning something like to derive formal arguments for primitive functions as well as the Sym class for the builtin symbol. As a macro_rules! macro, it could look something like
    formals! { PrimitivePaste, "..., sep = ' ', collapse = NULL" }
    
    This feels a bit clunky to me - especially if it would implement a trait. That definitely feels like something a proc macro should do.
    #[builtin("paste(..., sep = ' ', collapse = NULL)")]
    pub struct PrimitivePaste {}
    
    Probably requires that the r_derive proc macro crate is able to use the parsing component from the core language in order to parse this, which would mean...
  • [ ] Break up crate into separate crates as a workspace
  • [x] Want to do a clean-up pass on macros, removing anything that isn't widely used and standardizing the few that are.
  • [ ] Would like to explore ways to reduce the number of flavors of call_* and eval_*, etc that fuse things like argument matching, calling, evaluation and finalizing. Preferred outcomes would be an API that composes more nicely so that these behaviors can be built instead of individually handled:
    - stack.eval_and_finalize(expr)
    + stack.eval(expr).finalize()
    
    This would require that EvalResults carry a reference to the CallStack
  • [ ] Clean up Context implementations, as there is a lot of code lingering in the Environment implementation that is never called

dgkf avatar Aug 04 '24 20:08 dgkf

In the spirit of honing the scope of a few distinct crates, I'd like to explore decoupling the parsing from the evaluation a bit more consciously.

This is almost decoupled, but is tethered just a bit by the Expr::Primitive variant, which contains boxed references to actual functions. I'm exploring whether it's worth separating these steps so that the actual look-up of the primitive only happens upon evaluation, not during parsing.

Instead of

Expr::Call(Expr::Primitive(Box<InfixAdd>), ...)

We'd have

Expr::Call(CallKind::Infix, Expr::Symbol("+"), ...)

This would allow us to expose the parser to derive macros to declare the formal arguments in a proc macro instead of an inline macro.

dgkf avatar Aug 07 '24 03:08 dgkf

This design would be more difficult to deal with using things like Rs do.call - specifically for [ and ( if they’re being repurposed as vector and list constructor syntax.

In do.call, should they call the constructor or the indexing function?

To avoid this, I’m considering a design that looks like Julia’s juxtapose “function”, as a mechanism of differentiating these while still using simple S-expression like representations.

dgkf avatar Aug 14 '24 02:08 dgkf