summaryrefslogtreecommitdiff
path: root/lali.c
diff options
context:
space:
mode:
Diffstat (limited to 'lali.c')
-rw-r--r--lali.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/lali.c b/lali.c
new file mode 100644
index 0000000..15e90a2
--- /dev/null
+++ b/lali.c
@@ -0,0 +1,160 @@
+/*
+ * 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 "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;
+}