Skip to content

Commit

Permalink
Rewriting List internals and adding named subsets (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgkf authored Sep 29, 2023
1 parent dcf5fe4 commit 4e60cd9
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 87 deletions.
95 changes: 68 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# R

_An experimental implementation of R_
_An experimental implementation of R, with embellishments_

Check out the [live demo](https://dgkf.github.io/R/)

## What can it do?

```sh
cargo run
```
```r
# R version 0.0.1 -- "Why Not?"
# R version 0.3.0 -- "Days of Abandon"

x <- function(a = 1, ...) { a + c(...) }
# function(a = 1, ...) {
Expand All @@ -27,43 +29,82 @@ y(4, 3, 2, 1)
This amounts to (most) of R's grammar parsing, basic primitives, scope
management and ellipsis argument passing.

## What's different?

This project is not just a rewrite of R, but a playground for features and
reinterpretations. It is not meant to reimplement a compatible R layer, but
to rethink some of R's assumptions.

To start, there are a few superficial changes:

```r
# 'fn' keyword
f <- fn(a, b, c) {
a + b + c
}

# vector syntax
v <- [1, 2, 3, 4]

# list syntax
l <- (a = 1, b = 2, c = 3)

# lowercase keywords
kws <- (na, null, inf, true, false)
```

## Why

First and foremost, to learn.
This project is primarily a personal exploration into language design.

At the outset, many of the choices are researched one-by-one and are almost
certainly naive implementations. My goal is to learn and explore, and in
that way the project is already a success in my eyes. Beyond advancing my own
understanding of language internals, I'd love to see the project garner enough
interest to become self-sustaining.

If you see value in the project for anything beyond prototyping ideas, then
pushing the project toward something practical is contingent on your support.
Contributions, suggestions, feedback and testing are all appreciated.

### Values

I've always been interested in language design. I know `R` well and think it's a
super expressive language, so it felt like a good target to shoot for. Like any
long-time user of a language, I also have dreamt of how the language could be
improved. This project also offered a small testing ground for a few of those.
Being primarily a one-person project, the values currently map closely to my
own. Somethings I want to aim for:

## Long-term Goals
- A reasonably approachable language for R users (possibly with the ability to
interpret R code).
- Improved R constructs for complex calls, including argument packing and
unpacking, partial function calls, destructuring assignment
- Guardrails on non-standard-evaluation, allowing for user-facing
domain-specific-languages, while allowing a more rigid evaluation scheme
internally.
- Lean into the things that `rust` does well, such as threading, arguably
async evaluation, first-class data structures and algebraic error types.
- Learn from more general languages like `TypeScript` to better understand
how static typing can be comfortably embedded in a high-level language.

As to not mislead anyone, I want to be upfront in saying that this project is
well beyond what I can achieve alone.
## Contribution Guide

For this project to mature, it is going to need a community of contributors
with diverse expertise. I welcome anyone interested to help out, and I'm happy
to find an intersection of interests as we hash out what the language aims to
deliver.
If you also want to learn some `rust` or want to explore language design with
me, I'm happy to have you along for the ride. There are plenty of ways to
contribute. In order of increasing complexity, this might include:

That said, my personal ambitions for any spiritual successor to R would be:
- Documenting internals
- Improving documentation throughout
- Helping to improve the demo page hosted on GitHub pages
- Implementing new language concepts
- Providing feedback on internals

- Built with `R` code as a first-class input. Even if the language evolves past
`R`, I'd like for it to be able to leverage `R`'s package ecosystem.
- Reimagine many recent `R` language features without the confines of backwards
compatibility.
- Take Jan Vitek's analysis of R's performance to heart and bake in constructs
for isolating non-standard evaluation (though admittedly performance is a
distant goal at the moment).
- Leverage things that `rust` excels at, like its strong iterator support,
async/multithread execution and its error model.
Any and all contributions are appreciated, and you'll earn yourself a mention
in release notes!

## License

I welcome other contributors, but also have not thoughtfully selected a long-
term license yet. For now there's a CLA in place so that the license can
be altered later on. I don't intend to keep it around forever. If you have
suggestions or considerations for selecting an appropriate license, your
term license yet. For now there's a CLA in place so that the license can
be altered later on. I don't intend to keep it around forever. If you have
suggestions or considerations for selecting an appropriate license, your
feedback would be much appreciated.

My current preference is toward a copyleft license like GPL as opposed to a
Expand Down
14 changes: 14 additions & 0 deletions src/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,25 @@
# [1] 1 2 3 1000 5 6 7 8 9 10
```

* Mutating assignment implemented for `List`s, including by named index.

```r
x <- list(a = 1, b = 2, c = 3, d = 4, e = 5)
x[2:3][[1]] <- 200
x[1:4][c("d", "c")] <- 1000
x
# list(a = 1, b = 200, c = 1000, d = 1000, e = 5)
```

## Internals

* "altreps" are now supported internally, though currently only a "Subset"
(used for indexed assignment) is implemented.

* `List`s were reworked to use a `HashMap` of named values, allowing for
more immediate access to named values without repeated traversals of a
vector of pairs.


# 0.2.0 "In Bloom"

Expand Down
16 changes: 11 additions & 5 deletions src/lang.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::object::types::*;
use crate::object::*;
use crate::callable::core::{builtin, Callable};
use crate::error::*;
use crate::object::types::*;
use crate::object::*;

use core::fmt;
use std::fmt::Display;
Expand Down Expand Up @@ -287,8 +287,12 @@ fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option<String>) -> fmt
let v = x.values.borrow();
let s = x.subsets.clone();

let names: Vec<_> = x.values.borrow().clone().into_iter().map(|(n, _)| n).collect();
for (i, (_, si)) in s.bind_names(names).into_iter().take(v.len()).enumerate() {
for (i, (_, si)) in s
.bind_names(x.names.clone())
.into_iter()
.take(v.len())
.enumerate()
{
let name;
let value;

Expand Down Expand Up @@ -787,7 +791,9 @@ impl Context for Rc<Environment> {
match expr {
Expr::Null => Ok(Obj::Null),
Expr::NA => Ok(Obj::Vector(Vector::from(vec![OptionNA::NA as Logical]))),
Expr::Inf => Ok(Obj::Vector(Vector::from(vec![OptionNA::Some(f64::INFINITY)]))),
Expr::Inf => Ok(Obj::Vector(Vector::from(vec![OptionNA::Some(
f64::INFINITY,
)]))),
Expr::Number(x) => Ok(Obj::Vector(Vector::from(vec![x]))),
Expr::Integer(x) => Ok(Obj::Vector(Vector::from(vec![x]))),
Expr::Bool(x) => Ok(Obj::Vector(Vector::from(vec![OptionNA::Some(x)]))),
Expand Down
Loading

0 comments on commit 4e60cd9

Please sign in to comment.