~jack/misc

68a0c1caaf532ffc7b439b2e2d4f25316bde8e88 — Jack Kelly 6 months ago a3ca085
lambda-c: use custom refcount type instead of grefcount
M lambda-c/src/Makefile.am => lambda-c/src/Makefile.am +1 -0
@@ 8,6 8,7 @@ lambda_SOURCES = lambda.c \
	lexer.h \
	eval.c eval.h \
	parser.c parser.h \
	refcount.c refcount.h \
	term.c term.h

EXTRA_DIST = lexer.rl

M lambda-c/src/eval.c => lambda-c/src/eval.c +1 -1
@@ 55,7 55,7 @@ static Term*
sub(Term *t, const gchar *from, Term *to, gint *gensym_count) {
  switch (t->tag) {
  case TERM_VAR:
    return term_ref(strcmp(t->var.v, from) == 0 ? to : t);
    return strcmp(t->var.v, from) == 0 ? to : t;
  case TERM_APP:
    return term_app(sub(t->app.t1, from, to, gensym_count),
                    sub(t->app.t2, from, to, gensym_count));

M lambda-c/src/lambda.c => lambda-c/src/lambda.c +5 -3
@@ 29,15 29,17 @@
#include "parser.h"

int main(int argc, char *argv[]) {
  g_autoptr(GArray) tokens = lex("(\\x . \\y . x) y");
  g_autoptr(Term) t = parse(tokens);
  g_autoptr(GArray) tokens = lex("((\\w.\\x.\\y.\\z.(x)(w q))(y))(z)");
  Term *t = parse(tokens);

  term_fput(t, stdout);
  puts("");
  g_autoptr(Term) e = eval(t);
  Term *e = eval(t);
  printf("=> ");
  term_fput(e, stdout);
  puts("");

  term_unref(e);
  term_unref(t);
  return 0;
}

M lambda-c/src/parser.c => lambda-c/src/parser.c +0 -6
@@ 29,12 29,6 @@ static Term* parse_var(struct parser_state *st) {
  return term_var(t->v);
}

static Term* parse_app(struct parser_state *st) {
  Term *t1 = parse_rec(st);
  Term *t2 = parse_rec(st);
  return term_app(t1, t2);
}

static Term* parse_lam(struct parser_state *st) {
  expect_token(st, TOKEN_LAMBDA);
  const struct token *v = expect_token(st, TOKEN_VAR);

A lambda-c/src/refcount.c => lambda-c/src/refcount.c +57 -0
@@ 0,0 1,57 @@
/*
 * lambda-c: minimal lambda calculus interpreter
 * Copyright (C) 2021  Jack Kelly
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "config.h"
#include "refcount.h"

#include <stdio.h>
#include <stdlib.h>

void
refcount_init(struct refcount *rc) {
  rc->count = 1;
  rc->floating = 0;
}

void
refcount_init_floating(struct refcount *rc) {
  rc->count = 1;
  rc->floating = 1;
}

void
refcount_ref(struct refcount *rc) {
  rc->count++;
}

void
refcount_ref_sink(struct refcount *rc) {
  if (rc->floating) rc->floating = 0; else rc->count++;
}

int
refcount_unref(struct refcount *rc) {
  rc->count--;
  if (rc->count == 0) {
    return 1;
  } else if (rc->count < 0) {
    fprintf(stderr, "refcount underflow\n");
    abort();
  }
  return 0;
}

A lambda-c/src/refcount.h => lambda-c/src/refcount.h +36 -0
@@ 0,0 1,36 @@
/*
 * lambda-c: minimal lambda calculus interpreter
 * Copyright (C) 2021  Jack Kelly
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef REFCOUNT_H
#define REFCOUNT_H

struct refcount {
  int count;
  int floating;
};

void refcount_init(struct refcount *rc);
void refcount_init_floating(struct refcount *rc);

void refcount_ref(struct refcount *rc);
void refcount_ref_sink(struct refcount *rc);

/* return 1 if the thing being counted should be freed. */
int refcount_unref(struct refcount *rc);

#endif

M lambda-c/src/term.c => lambda-c/src/term.c +12 -6
@@ 22,7 22,7 @@
Term*
term_new(void) {
  struct term *r = g_new(struct term, 1);
  g_ref_count_init(&r->rc);
  refcount_init_floating(&r->rc);
  return r;
}



@@ 38,8 38,8 @@ Term*
term_app(Term *t1, Term *t2) {
  struct term *r = term_new();
  r->tag = TERM_APP;
  r->app.t1 = t1;
  r->app.t2 = t2;
  r->app.t1 = term_ref_sink(t1);
  r->app.t2 = term_ref_sink(t2);
  return r;
}



@@ 48,19 48,25 @@ term_lam(const gchar *v, Term *t) {
  struct term *r = term_new();
  r->tag = TERM_LAM;
  r->lam.v = g_strdup(v);
  r->lam.t = t;
  r->lam.t = term_ref_sink(t);
  return r;
}

Term*
term_ref(Term *t) {
  g_ref_count_inc(&t->rc);
  refcount_ref(&t->rc);
  return t;
}

Term*
term_ref_sink(Term *t) {
  refcount_ref_sink(&t->rc);
  return t;
}

void
term_unref(Term *t) {
  if (!g_ref_count_dec(&t->rc)) return;
  if (!refcount_unref(&t->rc)) return;

  switch (t->tag) {
  case TERM_VAR:

M lambda-c/src/term.h => lambda-c/src/term.h +4 -2
@@ 21,6 21,7 @@

#include <glib.h>
#include <stdio.h>
#include "refcount.h"

enum term_tag {
  TERM_VAR,


@@ 29,7 30,7 @@ enum term_tag {
};

typedef struct term {
  grefcount rc;
  struct refcount rc;
  enum term_tag tag;
  union {
    struct { gchar *v; } var;


@@ 38,12 39,13 @@ typedef struct term {
  };
} Term;

/* Copies the const ghcar* arguments but does not incref the Term* arguments. */
/* Copies const ghcar* args and takes the floating ref of Term* args. */
Term* term_var(const gchar *v);
Term* term_app(Term *t1, Term *t2);
Term* term_lam(const gchar *v, Term *t);

Term* term_ref(Term *t);
Term* term_ref_sink(Term *t);
void term_unref(Term *t);

G_DEFINE_AUTOPTR_CLEANUP_FUNC(Term, term_unref);