diff options
Diffstat (limited to 'work-in-progress/lali.c')
-rw-r--r-- | work-in-progress/lali.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/work-in-progress/lali.c b/work-in-progress/lali.c new file mode 100644 index 0000000..e0c0cbb --- /dev/null +++ b/work-in-progress/lali.c @@ -0,0 +1,173 @@ +/* + * lali (Lali Another Lisp Implementation) + * + * Author: Daniel Cerqueira (dan.git@lispclub.com) + * Maintainer: Daniel Cerqueira (dan.git@lispclub.com) + * Version: 0.0 + * Keywords: lali, lisp, implementation, interpreter, lisp1.5, + * computer programming language + * Homepage: https://gitlab.com/alexandre1985/lali + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright (C) 2025 Daniel Cerqueira + * + * This file is part of lali. + * + * lali is free software; you can redistribute it and/or modify it under + * the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <https://www.gnu.org/licenses/>. + * + * + * lali software is based on tiny-lisp <https://github.com/matp/tiny-lisp/> + * version from 2016, written by Matthias Pirstitz, which is released to public + * domain under Unlicense <https://unlicense.org/>. + */ + + +#include <sys/mman.h> +#include <sys/stat.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "liblali.h" + +#define YEARS "2025" + +// MAIN /////////////////////////////////////////////////////////////////////// + +void runFile(int infd, Object **env, GC_PARAM) { + Stream stream = { STREAM_TYPE_FILE, .fd = infd }; + GC_TRACE(gcObject, nil); + + if (setjmp(exceptionEnv)) + return; + + // deal with shebang + if (peekForward(&stream, true) == EOF) + return; + + do { + *gcObject = nil; + *gcObject = readExpr(&stream, GC_ROOTS); + evalExpr(gcObject, env, GC_ROOTS); + } while (peekNext(&stream) != EOF); +} + +void runREPL(int infd, Object **env, GC_PARAM) { + Stream stream = { STREAM_TYPE_FILE, .fd = infd }; + GC_TRACE(gcObject, nil); + + for (;;) { + if (setjmp(exceptionEnv)) + continue; + + for (;;) { + *gcObject = nil; + + fputs("lali> ", stdout); + fflush(stdout); + + if (peekNext(&stream) == EOF) { + fputc('\n', stdout); + return; + } + + *gcObject = readExpr(&stream, GC_ROOTS); + *gcObject = evalExpr(gcObject, env, GC_ROOTS); + + writeObject(*gcObject, true, stdout); + fputc('\n', stdout); + } + } +} + +int main(int argc, char *argv[]) { + int options = 0; + bool repl = false; + bool close = false; + bool quiet = false; + + if (argc >= 2) { + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { + fprintf(stderr, "basic usages:\nnormal: %s [file]...\nclose stdin: %s -c [file]...\nrun repl: %s -r [-q] [file]...\n\nin normal mode, reads from standard input.\nwhen present, load file(s) at startup. can be used as library file(s).\n", argv[0], argv[0], argv[0]); + return EXIT_SUCCESS; + } else if (!strcmp(argv[1], "-c")) { + options++; + close = true; + } else if (!strcmp(argv[1], "-r")) { + options++; + repl = true; + if (argc > 2 && !strcmp(argv[2], "-q")) { + options++; + quiet = true; + } + } else if (!strcmp(argv[1], "-q")) { + options++; + quiet = true; + if (argc > 2 && !strcmp(argv[2], "-r")) { + options++; + repl = true; + } + } else if (argv[1][0] == '-') { + fprintf(stderr, "%s: unrecognized option, `%s'\n", argv[0], argv[1]); + return EXIT_FAILURE; + } + } + + GC_PARAM = nil; + + if (setjmp(exceptionEnv)) + return EXIT_FAILURE; + + symbols = nil; + symbols = newCons(&nil, &symbols, GC_ROOTS); + symbols = newCons(&n, &symbols, GC_ROOTS); + symbols = newCons(&t, &symbols, GC_ROOTS); + symbols = newCons(&f, &symbols, GC_ROOTS); + + GC_TRACE(gcEnv, newRootEnv(GC_ROOTS)); + + int fd = 0; + + if (argc > 1) { + for (int i = ++options; i < argc; i++) { + if ((fd = open(argv[i], O_RDONLY)) == -1) { + fprintf(stderr, "%s: open() failed, %s\n", argv[0], strerror(errno)); + return EXIT_FAILURE; + } + runFile(fd, gcEnv, GC_ROOTS); + } + } + + if (repl) { + if(!isatty(STDIN_FILENO)) { + fprintf(stderr, "%s: repl does not accept piping\n", argv[0]); + return EXIT_FAILURE; + } + + if (!quiet) + fprintf(stdout, "lali Copyright (C) %s Daniel Cerqueira\n\nThis is free software: you are free to change and redistribute it,\nunder certain conditions.\nThis program comes with NO WARRANTY, to the extent permitted by law.\n", YEARS); + + runREPL(STDIN_FILENO, gcEnv, GC_ROOTS); + } + else if (!close) + runFile(STDIN_FILENO, gcEnv, GC_ROOTS); + + return EXIT_SUCCESS; +} |