Skip to content

Instantly share code, notes, and snippets.

@Tpaefawzen
Last active February 18, 2026 11:29
Show Gist options
  • Select an option

  • Save Tpaefawzen/b2135c68573c65cb0a7f99cf5c82ffef to your computer and use it in GitHub Desktop.

Select an option

Save Tpaefawzen/b2135c68573c65cb0a7f99cf5c82ffef to your computer and use it in GitHub Desktop.
Wip: implement Grass (Ueno, 2006) without pushing global and local values to data stack

How I want to implement Data

Each data is represented as unsigned integer. 0-255 as such Byte, 256 as I, 257 as K, 258 as KI, 259 as read, 260 as next, 261 as out, n>=262 if n is even as N-th code, else n is odd as N-th previous item on data stack.

Alternative

n>=262 where

  • n%3 == 0 as code
  • n%3 == 1 as global Data item
  • otherwise as local Data item

Hoe it should be compiled

Every abstraction goes to Code area:

Each local function is encoded to the following sequence:

  1. Number of applications
  2. Number of arguments
  3. Each application

Every application goes to either Global Code or into Abstraction body. Represented as a pair of Data

Example

Program wWWwwww

$local_data = [
   256, 259,
   256, 119,
   256, 260,
   256, 261,
];
$global_data = undef;

@code = (
   1, 1,
   (260+(2-1)*2+0), (260+(4-1)*2+0),
);
$current_source = [
   256, (260+0+1), # wWWwwwwv on @code[0..]
];

# Step 1
push @$local_data, $current_source->[0..2];

# Step 2
!defined($currrent_source->[2]);

# Step 3
## Resolve $local_data->[-2..]

Issue with my current idea

Consider you have a function to take 2 items and call with f00 a00 a01, and it returns f05a a00 a01 a02 a03 a04 a05 a06 a07 when the function wants two more arguments to get evaluated: it is a problem where to store such thing.

One idea is to make other memory: say @allocated, and you have Data (~0), (~1), (~2), ... to indicate @allocated index.

@global_data_stack = (
256, $read,
256, 119,
256, $next,
256, $out,
256, 119,
256, 118,
);
@global_code = (
data(1), data(0), # @119 @118 = False
data(2), data(2), # @119 @119 = True
256, code(0), # I I,
256, code(2),
);
@abs_code = (
length(0), args(1), # I
length(3), args(1), data(6), data
length(2), args(2), data(1), data(0), data(2), data(0), # church number two
length(1), args(1), data(
);
$globals = undef;
$args = undef;
$locals = \@global_data_stack;
{
package Lang::Grass::SourceIterator;
# Constructor
sub fromGlobal {
my ($class, $source) = @_;
bless $class, { src => $source, idx => 0, end => scalar @$source, };
}
# Constructor; expects array pointer to start of local function
sub fromLocal {
my ($class, $source) = @_;
bless $class, { src => $source->[2..], idx => 0, end => $source->[1], };
}
sub next {
my $self = @_;
return (undef, undef) if $self->{idx} >= $self->end;
my ($f, $a) = @$self->{src};
$self->{idx} += 2;
($f, $a);
}
sub hasNext {
my $self = @_;
$self->{idx} < $self->{end};
}
1;
}
my $src_itr = Lang::Grass::SourceIterator->fromGlobal(\@global_code);
while (my ($f, $a) = $src_itr->next()) {
push @$locals, $f, $a;
resolveLatest($locals, $args, $globals, \@global_code);
}
push @$locals, data(0), data(0);
resolveLatest($locals, $args, $globals, \@global_code);
sub resolveLatest {
my ($locals, $args, $globals, $code) = @_;
my ($f, $a) = $locals->[$i..];
if (my $data_back_idx = unpackDataIdx($f)) {
my $depth = 0; ...;
}
if ($f == 256) {
push @$locals, $f, $a;
} elsif (0 <= $f && $f <= 255) {
push @$locals, 256, ($f == $a ? 257 : 258);
} elsif ($f == 257 || $f == 258) {
unreachable();
} elsif ($f == 259 || $f == 260 || $f == 261) {
unreachable();
} else {
my $f = $f - 262;
if ($f % 2 == 0) {
my $code_idx = $f / 2;
push @$
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment