~brenns10/funlisp

cbd0dc556057ec9c60decfe0ce28b1de69c7e3f2 — Stephen Brennan 1 year, 5 months ago c4e4105
Implement syntax sugar for getattr
2 files changed, 69 insertions(+), 1 deletions(-)

M scripts/tests/modules.lisp
M src/parse.c
M scripts/tests/modules.lisp => scripts/tests/modules.lisp +4 -0
@@ 1,5 1,9 @@
(assert (equal? '(getattr a 'b) 'a.b))
(assert (equal? '(getattr (getattr one 'two) 'three) 'one.two.three))

(import example)

(assert (equal? (getattr example 'foo) "bar"))
(assert (equal? example.foo "bar"))

; OUTPUT(0)

M src/parse.c => src/parse.c +65 -1
@@ 175,21 175,85 @@ static result lisp_parse_list_or_sexp(lisp_runtime *rt, char *input, int index)
	}
}

static lisp_value *split_symbol(lisp_runtime *rt, char *string, int dotcount, int remain)
{
	char *delim, *tok;
	int i, len;
	lisp_value *prev = NULL;
	lisp_symbol *sym;
	lisp_list *list;
	lisp_symbol *getattr = lisp_symbol_new(rt, "getattr", 0);

	/* Create the first symbol, which is the left hand side */
	delim = strchr(string, '.');
	len = (int) (delim - string);
	tok = malloc(len + 1);
	strncpy(tok, string, len);
	tok[len] = '\0';
	sym = lisp_symbol_new(rt, tok, LS_OWN);
	prev = (lisp_value*) sym;
	string = delim + 1;
	remain -= len + 1;

	/* Create a "getattr" for each right hand side remaining */
	for (i = 0; i < dotcount; i++) {
		/* Attribute symbol */
		if (i < dotcount - 1) {
			delim = strchr(string, '.');
			len = (int) (delim - string);
		} else {
			len = remain;
		}
		tok = malloc(len + 1);
		strncpy(tok, string, len);
		tok[len] = '\0';
		sym = lisp_symbol_new(rt, tok, LS_OWN);

		/* Create (getattr PREV 'tok) */
		list = lisp_list_new(rt,
			(lisp_value *) getattr,
			(lisp_value *) lisp_list_new(rt,
				prev,
				(lisp_value *) lisp_list_new(rt,
					(lisp_value *) lisp_quote_with(rt, (lisp_value *) sym, "quote"),
					lisp_nil_new(rt)
				)
			)
		);
		prev = (lisp_value *) list;
		string = delim + 1;
		remain -= len + 1;
	}
	return prev;
}

static result lisp_parse_symbol(lisp_runtime *rt, char *input, int index)
{
	int n = 0;
	int dotcount = 0;
	char *copy;
	lisp_symbol *s;

	while (input[index + n] && !isspace(input[index + n]) &&
	       input[index + n] != ')' && input[index + n] != '.' &&
	       input[index + n] != ')' && /* input[index + n] != '.' && */
	       input[index + n] != '\'' && input[index + n] != COMMENT) {
		if (input[index + n] == '.')
			dotcount++;
		n++;
	}
	if (!input[index]) {
		rt->error = "unexpected eof while parsing symbol";
		return_result_err(NULL, index, LE_EOF);
	}

	if (dotcount) {
		if (input[index] == '.' || input[index + n - 1] == '.') {
			rt->error = "unexpected '.' at beginning or end of symbol";
			return_result_err(NULL, index, LE_SYNTAX);
		}
		return_result(split_symbol(rt, input + index, dotcount, n), index + n);
	}

	copy = malloc(n + 1);
	strncpy(copy, input + index, n);
	copy[n] = '\0';