1
0
Fork 0
lesson-lisp/src/builtins.c

716 lines
20 KiB
C
Raw Normal View History

2023-05-04 11:18:16 +00:00
#include "builtins.h"
2023-05-05 14:46:15 +00:00
#include "lexer.h"
2023-05-04 17:41:53 +00:00
#include "object.h"
2023-05-06 16:35:04 +00:00
#include "parser.h"
2023-05-05 14:46:15 +00:00
#include "tokens.h"
2023-05-04 17:41:53 +00:00
2023-05-04 11:18:16 +00:00
#include <assert.h>
#include <stddef.h>
2023-05-04 14:34:14 +00:00
#include <stdio.h>
2023-05-04 11:18:16 +00:00
#include <stdlib.h>
#include <string.h>
2023-05-06 19:13:35 +00:00
// Assertions
static struct Object *func_assert_equal(size_t args_count, struct Object **args_array);
static struct Object *func_assert_false(size_t args_count, struct Object **args_array);
static struct Object *func_assert_true(size_t args_count, struct Object **args_array);
2023-05-06 18:31:07 +00:00
// Arcana Lisp internals
2023-05-07 12:06:16 +00:00
static struct Object *func_arcana_SLASH_builtin(size_t args_count, struct Object **args_array);
2023-05-06 18:31:07 +00:00
static struct Object *func_arcana_SLASH_parse(size_t args_count, struct Object **args_array);
static struct Object *func_arcana_SLASH_tokenize(size_t args_count, struct Object **args_array);
static struct Object *func_arcana_SLASH_typeof(size_t args_count, struct Object **args_array);
2023-05-09 09:27:59 +00:00
// Freezing
static struct Object *func_freeze(size_t args_count, struct Object **args_array);
static struct Object *func_frozen_QN(size_t args_count, struct Object **args_array);
2023-05-04 14:51:07 +00:00
// Basic data structures
2023-05-05 15:29:14 +00:00
static struct Object *func_car(size_t args_count, struct Object **args_array);
static struct Object *func_cdr(size_t args_count, struct Object **args_array);
static struct Object *func_cons(size_t args_count, struct Object **args_array);
static struct Object *func_list(size_t args_count, struct Object **args_array);
2023-05-06 17:26:27 +00:00
// Equivalence predicates
static struct Object *func_equal_QN(size_t args_count, struct Object **args_array);
2023-05-09 08:41:58 +00:00
// Type equivalence predicates
static struct Object *func_boolean_EQ_QN(size_t args_count, struct Object **args_array);
static struct Object *func_symbol_EQ_QN(size_t args_count, struct Object **args_array);
2023-05-04 21:31:56 +00:00
// Type conversion
static struct Object *func_number_TO_string(size_t args_count, struct Object **args_array);
static struct Object *func_string_TO_symbol(size_t args_count, struct Object **args_array);
static struct Object *func_symbol_TO_string(size_t args_count, struct Object **args_array);
2023-05-05 11:50:52 +00:00
// Arithmetic operators
2023-05-05 15:29:14 +00:00
static struct Object *func_EQ(size_t args_count, struct Object **args_array);
2023-05-05 20:16:24 +00:00
static struct Object *func_PLUS(size_t args_count, struct Object **args_array);
2023-05-05 20:24:35 +00:00
static struct Object *func_MINUS(size_t args_count, struct Object **args_array);
2023-05-04 14:34:14 +00:00
// IO
2023-05-05 15:29:14 +00:00
static struct Object *func_display(size_t args_count, struct Object **args_array);
static struct Object *func_newline(size_t args_count, struct Object **args_array);
2023-05-04 11:18:16 +00:00
2023-05-09 09:27:59 +00:00
#define BUILTIN(name_str, func_name) { \
.type = TYPE_PROCEDURE, \
.is_frozen = true, \
.procedure = { \
.name = name_str, \
.func = func_##func_name, \
}, \
}
2023-05-04 17:41:53 +00:00
static struct Object builtins[] = {
2023-05-06 19:13:35 +00:00
// Assertions
2023-05-09 09:27:59 +00:00
BUILTIN("assert-equal", assert_equal),
BUILTIN("assert-false", assert_false),
BUILTIN("assert-true", assert_true),
2023-05-06 18:31:07 +00:00
// Arcana Lisp internals
2023-05-09 09:27:59 +00:00
BUILTIN("arcana/builtin", arcana_SLASH_builtin),
BUILTIN("arcana/parse", arcana_SLASH_parse),
BUILTIN("arcana/tokenize", arcana_SLASH_tokenize),
BUILTIN("arcana/typeof", arcana_SLASH_typeof),
// Freezing
BUILTIN("freeze", freeze),
BUILTIN("frozen?", frozen_QN),
2023-05-04 14:51:07 +00:00
// Basic data structures
2023-05-09 09:27:59 +00:00
BUILTIN("car", car),
BUILTIN("cdr", cdr),
BUILTIN("cons", cons),
BUILTIN("list", list),
2023-05-06 17:26:27 +00:00
// Equivalence predicates
2023-05-09 09:27:59 +00:00
BUILTIN("equal?", equal_QN),
2023-05-09 08:41:58 +00:00
// Type equivalence predicates
2023-05-09 09:27:59 +00:00
BUILTIN("boolean=?", boolean_EQ_QN),
BUILTIN("symbol=?", symbol_EQ_QN),
2023-05-04 21:31:56 +00:00
// Type conversion
2023-05-09 09:27:59 +00:00
BUILTIN("number->string", number_TO_string),
BUILTIN("string->symbol", string_TO_symbol),
BUILTIN("symbol->string", symbol_TO_string),
2023-05-05 11:50:52 +00:00
// Arithmetic operators
2023-05-09 09:27:59 +00:00
BUILTIN("=", EQ),
BUILTIN("+", PLUS),
BUILTIN("-", MINUS),
2023-05-04 14:34:14 +00:00
// IO
2023-05-09 09:27:59 +00:00
BUILTIN("display", display),
BUILTIN("newline", newline),
2023-05-05 20:16:24 +00:00
// NULL
2023-05-09 09:27:59 +00:00
{ .type = TYPE_PROCEDURE, .is_frozen = true, .procedure = { NULL, NULL } },
2023-05-04 11:18:16 +00:00
};
2023-05-04 17:50:02 +00:00
struct Object *builtins_get(const char *name)
2023-05-04 11:18:16 +00:00
{
2023-05-04 17:41:53 +00:00
for (size_t index = 0; builtins[index].procedure.name; ++index) {
if (strcmp(name, builtins[index].procedure.name) == 0) {
return &builtins[index];
2023-05-04 11:18:16 +00:00
}
}
2023-05-04 18:14:13 +00:00
return NULL;
2023-05-04 11:18:16 +00:00
}
2023-05-06 19:13:35 +00:00
/**************
* Assertions *
**************/
struct Object *func_assert_equal(
size_t args_count,
struct Object **args_array
) {
struct Object *const result = func_equal_QN(args_count, args_array);
if (!Object_is_true(result)) exit(EXIT_FAILURE);
return NULL;
}
struct Object *func_assert_false(
size_t args_count,
struct Object **args_array
) {
assert(args_count == 1);
if (!Object_is_false(args_array[0])) exit(EXIT_FAILURE);
return NULL;
}
struct Object *func_assert_true(
size_t args_count,
struct Object **args_array
) {
assert(args_count == 1);
if (!Object_is_true(args_array[0])) exit(EXIT_FAILURE);
return NULL;
}
2023-05-06 18:31:07 +00:00
/*************************
* Arcana Lisp internals *
*************************/
2023-05-05 14:46:15 +00:00
2023-05-07 12:06:16 +00:00
struct Object *func_arcana_SLASH_builtin(
size_t args_count,
struct Object **args_array
) {
assert(args_count == 1);
struct Object *const name = args_array[0];
assert(Object_is_symbol(name));
return builtins_get(name->s);
}
2023-05-06 18:31:07 +00:00
struct Object *func_arcana_SLASH_parse(
2023-05-06 16:35:04 +00:00
size_t args_count,
struct Object **args_array
) {
assert(args_count == 1);
assert(args_array);
struct Object *tokens_obj = args_array[0];
assert(OBJECT_IS_LIST_HEAD(tokens_obj));
const Tokens tokens = Tokens_new();
assert(tokens);
while (!OBJECT_IS_NULL(tokens_obj)) {
assert(Object_is_pair(tokens_obj));
struct Object *const token_obj = tokens_obj->pair.car;
assert(Object_is_pair(token_obj));
struct Object *const type_obj = token_obj->pair.car;
assert(Object_is_symbol(type_obj));
struct Object *const val_obj = token_obj->pair.cdr;
assert(Object_is_string(val_obj));
enum TokenType token_type;
if (strcmp(type_obj->s, "TOKEN_ROUND_OPEN") == 0) {
token_type = TOKEN_ROUND_OPEN;
} else if (strcmp(type_obj->s, "TOKEN_ROUND_CLOSE") == 0) {
token_type = TOKEN_ROUND_CLOSE;
} else if (strcmp(type_obj->s, "TOKEN_SQUARE_OPEN") == 0) {
token_type = TOKEN_SQUARE_OPEN;
} else if (strcmp(type_obj->s, "TOKEN_SQUARE_CLOSE") == 0) {
token_type = TOKEN_SQUARE_CLOSE;
} else if (strcmp(type_obj->s, "TOKEN_CURLY_OPEN") == 0) {
token_type = TOKEN_CURLY_OPEN;
} else if (strcmp(type_obj->s, "TOKEN_CURLY_CLOSE") == 0) {
token_type = TOKEN_CURLY_CLOSE;
} else if (strcmp(type_obj->s, "TOKEN_QUOTE") == 0) {
token_type = TOKEN_QUOTE;
} else if (strcmp(type_obj->s, "TOKEN_QUASI_QUOTE") == 0) {
token_type = TOKEN_QUASI_QUOTE;
} else if (strcmp(type_obj->s, "TOKEN_QUASI_UNQUOTE") == 0) {
token_type = TOKEN_QUASI_UNQUOTE;
2023-05-06 16:35:04 +00:00
} else if (strcmp(type_obj->s, "TOKEN_TAG") == 0) {
token_type = TOKEN_TAG;
} else if (strcmp(type_obj->s, "TOKEN_IDENT") == 0) {
token_type = TOKEN_IDENT;
} else if (strcmp(type_obj->s, "TOKEN_NUM") == 0) {
token_type = TOKEN_NUM;
} else if (strcmp(type_obj->s, "TOKEN_STRING") == 0) {
token_type = TOKEN_STRING;
} else {
assert(0);
}
Tokens_append(tokens, token_type, val_obj->s);
tokens_obj = tokens_obj->pair.cdr;
}
struct Object *const program = parse(tokens);
Tokens_delete(tokens);
return program;
}
2023-05-06 18:31:07 +00:00
struct Object *func_arcana_SLASH_tokenize(
2023-05-05 15:29:14 +00:00
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
assert(args_array);
struct Object *const str_obj = args_array[0];
2023-05-05 14:46:15 +00:00
assert(Object_is_string(str_obj));
2023-05-05 15:29:14 +00:00
2023-05-05 14:46:15 +00:00
const char *const str = str_obj->s;
assert(str);
Tokens tokens = Tokens_new();
assert(tokens);
Lexer lexer = Lexer_new(tokens);
assert(lexer);
for (const char *chr = str; *chr; ++chr) {
Lexer_lex(lexer, *chr);
}
Lexer_lex(lexer, '\n');
LEXER_DELETE(lexer);
2023-05-07 11:16:53 +00:00
struct Object *list = NULL;
if (Tokens_top(tokens)) {
struct Object *last = NULL;
list = Object_new_pair(
2023-05-05 14:46:15 +00:00
Object_new_pair(
Object_new_symbol(TokenType_to_str(Tokens_top(tokens)->type)),
Object_new_string(Tokens_top(tokens)->val)
),
NULL
);
Tokens_pop(tokens);
2023-05-07 11:16:53 +00:00
while (Tokens_top(tokens)) {
struct Object *const new_pair = Object_new_pair(
Object_new_pair(
Object_new_symbol(TokenType_to_str(Tokens_top(tokens)->type)),
Object_new_string(Tokens_top(tokens)->val)
),
NULL
);
Tokens_pop(tokens);
if (last) {
last->pair.cdr = new_pair;
last = new_pair;
} else {
last = new_pair;
list->pair.cdr = last;
}
2023-05-05 14:46:15 +00:00
}
}
TOKENS_DELETE(tokens);
return list;
}
2023-05-06 18:31:07 +00:00
struct Object *func_arcana_SLASH_typeof(
2023-05-05 22:05:04 +00:00
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
assert(args_array);
struct Object *const object = args_array[0];
if (OBJECT_IS_NULL(object)) return Object_new_symbol("null");
switch (object->type) {
case TYPE_PROCEDURE: return Object_new_symbol("procedure");
case TYPE_PAIR: return Object_new_symbol("pair");
case TYPE_BOOLEAN: return Object_new_symbol("boolean");
case TYPE_CHAR: return Object_new_symbol("char");
case TYPE_SYMBOL: return Object_new_symbol("symbol");
case TYPE_STRING: return Object_new_symbol("string");
case TYPE_NUMBER: return Object_new_symbol("number");
}
assert(0);
return NULL;
}
2023-05-09 09:27:59 +00:00
/************
* Freezing *
************/
struct Object *func_freeze(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
if (!OBJECT_IS_NULL(args_array[0])) args_array[0]->is_frozen = true;
return args_array[0];
}
struct Object *func_frozen_QN(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
return Object_new_boolean(
OBJECT_IS_NULL(args_array[0]) ||
args_array[0]->is_frozen
);
}
2023-05-04 14:51:07 +00:00
/*************************
* Basic data structures *
*************************/
2023-05-04 12:09:50 +00:00
2023-05-05 15:29:14 +00:00
struct Object *func_car(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
2023-05-04 21:55:59 +00:00
2023-05-05 15:29:14 +00:00
struct Object *const arg = args_array[0];
2023-05-04 21:55:59 +00:00
assert(Object_is_pair(arg));
2023-05-05 20:49:04 +00:00
return arg->pair.car;
2023-05-04 21:55:59 +00:00
}
2023-05-05 15:29:14 +00:00
struct Object *func_cdr(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
2023-05-04 21:55:59 +00:00
2023-05-05 15:29:14 +00:00
struct Object *const arg = args_array[0];
2023-05-04 21:55:59 +00:00
assert(Object_is_pair(arg));
2023-05-05 20:49:04 +00:00
return arg->pair.cdr;
2023-05-04 21:55:59 +00:00
}
2023-05-05 15:29:14 +00:00
struct Object *func_cons(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 2);
return Object_new_pair(args_array[0], args_array[1]);
2023-05-04 12:09:50 +00:00
}
2023-05-05 15:29:14 +00:00
struct Object *func_list(
const size_t args_count,
struct Object **const args_array
) {
if (args_count == 0) return NULL;
return Object_new_pair(
args_array[0],
func_list(args_count - 1, &args_array[1])
);
2023-05-05 07:30:45 +00:00
}
2023-05-06 17:26:27 +00:00
/**************************
* Equivalence predicates *
**************************/
struct Object *func_equal_QN(
2023-05-09 08:41:58 +00:00
const size_t args_count,
2023-05-06 17:26:27 +00:00
struct Object **const args_array
) {
if (args_count <= 1) return Object_new_boolean(true);
struct Object *const first = args_array[0];
struct Object *const result = Object_new_boolean(true);
for (size_t index = 1; result->boolean && index < args_count; ++index) {
struct Object *const curr = args_array[index];
if (OBJECT_IS_NULL(first)) {
if (!OBJECT_IS_NULL(curr)) result->boolean = false;
} else {
if (curr->type != first->type) {
result->boolean = false;
break;
}
switch (first->type) {
case TYPE_PROCEDURE:
2023-05-09 09:27:59 +00:00
// Built-in
if (first->procedure.func) {
result->boolean =
curr->procedure.func &&
!strcmp(first->procedure.name, curr->procedure.name);
}
// Lambda
else {
result->boolean = curr == first;
}
2023-05-06 17:26:27 +00:00
break;
case TYPE_PAIR:
{
struct Object *car_args[2] =
{ first->pair.car, curr->pair.car };
struct Object *cdr_args[2] =
{ first->pair.cdr, curr->pair.cdr };
struct Object *car_obj = func_equal_QN(2, car_args);
struct Object *cdr_obj = func_equal_QN(2, cdr_args);
assert(Object_is_boolean(car_obj));
assert(Object_is_boolean(cdr_obj));
result->boolean = car_obj->boolean && cdr_obj->boolean;
break;
}
case TYPE_BOOLEAN:
result->boolean = first->boolean == curr->boolean;
break;
case TYPE_CHAR:
result->boolean = first->chr == curr->chr;
break;
case TYPE_SYMBOL:
case TYPE_STRING:
result->boolean = !strcmp(first->s, curr->s);
break;
case TYPE_NUMBER:
result->boolean = first->number.i64 == curr->number.i64;
break;
}
}
2023-05-09 08:41:58 +00:00
}
return result;
}
/*******************************
* Type equivalence predicates *
*******************************/
struct Object *func_boolean_EQ_QN(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count > 0);
struct Object *const first = args_array[0];
assert(Object_is_boolean(first));
struct Object *const result = Object_new_boolean(true);
for (size_t index = 1; result->boolean && index < args_count; ++index) {
assert(Object_is_boolean(args_array[index]));
}
for (size_t index = 1; result->boolean && index < args_count; ++index) {
struct Object *const curr = args_array[index];
if (curr->boolean != first->boolean) result->boolean = false;
}
return result;
}
struct Object *func_symbol_EQ_QN(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count > 0);
struct Object *const first = args_array[0];
assert(Object_is_symbol(first));
struct Object *const result = Object_new_boolean(true);
for (size_t index = 1; result->boolean && index < args_count; ++index) {
assert(Object_is_symbol(args_array[index]));
}
for (size_t index = 1; result->boolean && index < args_count; ++index) {
struct Object *const curr = args_array[index];
if (strcmp(curr->s, first->s)) result->boolean = false;
2023-05-06 17:26:27 +00:00
}
return result;
}
2023-05-04 21:31:56 +00:00
/*******************
* Type conversion *
*******************/
struct Object *func_number_TO_string(
2023-05-05 15:29:14 +00:00
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1 || args_count == 2);
struct Object *const z = args_array[0];
2023-05-04 21:31:56 +00:00
assert(Object_is_number(z));
2023-05-05 15:29:14 +00:00
2023-05-04 21:31:56 +00:00
int64_t radix = 10;
2023-05-05 15:29:14 +00:00
if (args_count == 2) {
struct Object *radix_obj = args_array[1];
2023-05-04 21:31:56 +00:00
assert(Object_is_number(radix_obj));
2023-05-06 11:05:33 +00:00
radix = radix_obj->number.i64;
2023-05-04 21:31:56 +00:00
}
char buffer[70];
switch (radix) {
case 2:
assert(0); // TODO
break;
case 8:
2023-05-06 11:05:33 +00:00
snprintf(buffer, 70, "%lo", z->number.i64);
2023-05-04 21:31:56 +00:00
break;
case 10:
2023-05-06 11:05:33 +00:00
snprintf(buffer, 70, "%ld", z->number.i64);
2023-05-04 21:31:56 +00:00
break;
case 16:
2023-05-06 11:05:33 +00:00
snprintf(buffer, 70, "%lx", z->number.i64);
2023-05-04 21:31:56 +00:00
break;
default:
assert(0);
}
return Object_new_string(buffer);
}
struct Object *func_string_TO_symbol(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
struct Object *const string = args_array[0];
assert(Object_is_string(string));
return Object_new_symbol(string->s);
}
struct Object *func_symbol_TO_string(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
struct Object *const symbol = args_array[0];
assert(Object_is_symbol(symbol));
return Object_new_string(symbol->s);
}
2023-05-05 11:50:52 +00:00
/************************
* Arithmetic operators *
************************/
2023-05-05 15:29:14 +00:00
struct Object *func_EQ(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count >= 1);
struct Object *const first = args_array[0];
assert(Object_is_number(first));
2023-05-05 11:50:52 +00:00
2023-05-05 15:29:14 +00:00
struct Object *const result = Object_new_boolean(true);
2023-05-05 11:50:52 +00:00
2023-05-05 15:29:14 +00:00
for (size_t index = 1; index < args_count; ++index) {
struct Object *const cur = args_array[index];
assert(Object_is_number(cur));
2023-05-05 11:50:52 +00:00
2023-05-06 11:05:33 +00:00
if (cur->number.i64 != first->number.i64) {
2023-05-05 15:29:14 +00:00
result->boolean = false;
break;
}
}
return result;
2023-05-05 11:50:52 +00:00
}
2023-05-05 20:16:24 +00:00
struct Object *func_PLUS(
const size_t args_count,
struct Object **const args_array
) {
struct Object *const object = Object_new_number(0);
if (args_count == 0) return object;
struct Object *const arg = args_array[0];
assert(Object_is_number(arg));
2023-05-06 11:05:33 +00:00
object->number.i64 = arg->number.i64;
2023-05-05 20:16:24 +00:00
if (args_count == 1) return object;
struct Object *const b_sum = func_PLUS(args_count - 1, &args_array[1]);
2023-05-06 11:05:33 +00:00
object->number.i64 += b_sum->number.i64;
2023-05-05 20:16:24 +00:00
return object;
}
2023-05-05 20:24:35 +00:00
struct Object *func_MINUS(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count >= 1);
struct Object *const arg = args_array[0];
assert(Object_is_number(arg));
2023-05-06 11:05:33 +00:00
struct Object *const object = Object_new_number(arg->number.i64);
2023-05-05 20:24:35 +00:00
if (args_count >= 2) {
struct Object *const sum = func_PLUS(args_count - 1, &args_array[1]);
assert(Object_is_number(sum));
2023-05-06 11:05:33 +00:00
object->number.i64 -= sum->number.i64;
2023-05-05 20:24:35 +00:00
}
return object;
}
2023-05-04 14:34:14 +00:00
/******
* IO *
******/
static void display_pair(struct Object *pair);
2023-05-05 15:29:14 +00:00
struct Object *func_display(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 1);
2023-05-04 14:34:14 +00:00
2023-05-05 15:29:14 +00:00
struct Object *const object = args_array[0];
2023-05-04 14:34:14 +00:00
if (!object) {
printf("()");
return NULL;
}
switch (object->type) {
2023-05-04 17:24:54 +00:00
case TYPE_PROCEDURE:
if (object->procedure.name) {
printf("#<procedure:%s>", object->procedure.name);
} else {
printf("#<procedure>");
}
break;
2023-05-04 14:34:14 +00:00
case TYPE_PAIR:
printf("(");
display_pair(object);
printf(")");
break;
case TYPE_BOOLEAN:
2023-05-05 10:03:32 +00:00
printf("%s", object->boolean ? "#true" : "#false");
2023-05-04 14:34:14 +00:00
break;
case TYPE_CHAR:
printf("#\\TODO"); // TODO
break;
case TYPE_SYMBOL:
printf("%s", object->s);
break;
case TYPE_NUMBER:
2023-05-06 11:05:33 +00:00
printf("%li", object->number.i64);
2023-05-04 14:34:14 +00:00
break;
2023-05-05 20:06:04 +00:00
case TYPE_STRING:
2023-05-07 11:01:02 +00:00
putchar('"');
for (char *str = object->s; *str; ++str) {
const char chr = *str;
if (chr == '\\') {
printf("\\\\");
} else if (chr == '\"') {
printf("\\\"");
} else {
putchar(chr);
}
}
putchar('"');
2023-05-05 20:06:04 +00:00
break;
2023-05-04 14:34:14 +00:00
}
return NULL;
}
2023-05-05 15:29:14 +00:00
struct Object *func_newline(
const size_t args_count,
struct Object **const args_array
) {
assert(args_count == 0);
(void)args_array;
2023-05-04 14:34:14 +00:00
printf("\n");
return NULL;
}
void display_pair(struct Object *const pair)
{
2023-05-05 22:42:34 +00:00
assert(Object_is_pair(pair));
2023-05-04 14:34:14 +00:00
2023-05-05 22:42:34 +00:00
struct Object *pair1[2] = { pair->pair.car, NULL };
2023-05-05 15:29:14 +00:00
func_display(1, pair1);
2023-05-04 14:34:14 +00:00
2023-05-05 20:49:04 +00:00
if (!pair->pair.cdr) return;
2023-05-04 14:34:14 +00:00
printf(" ");
2023-05-05 22:42:34 +00:00
if (Object_is_pair(pair->pair.cdr)) {
2023-05-05 20:49:04 +00:00
display_pair(pair->pair.cdr);
2023-05-04 14:34:14 +00:00
return;
}
printf(". ");
2023-05-05 22:42:34 +00:00
struct Object *pair2[2] = { pair->pair.cdr, NULL };
2023-05-05 15:29:14 +00:00
func_display(1, pair2);
2023-05-04 14:34:14 +00:00
}