Move main() etc. into main.c

This commit is contained in:
Sage Vaillancourt 2022-04-05 20:05:58 -04:00
parent 5ca9fdb042
commit fc4f0bef28
6 changed files with 256 additions and 197 deletions

View File

@ -1,4 +1,4 @@
files = pebblisp.c tokens.c object.c env.c web.c plfunc.c hash.c files = main.c pebblisp.c tokens.c object.c env.c web.c plfunc.c hash.c
libs = -lreadline -lmicrohttpd libs = -lreadline -lmicrohttpd
exe = pl exe = pl

View File

@ -25,13 +25,6 @@
(def reloadConfig (fn () (loadfile config))) (def reloadConfig (fn () (loadfile config)))
(def hour (fn (ti) (
(def h (% ti.hour 12))
(if (= 0 h) 12 h)
)))
(def zero (fn (num) (cat (if (< num 10) "0" "") num)))
(def string (fn (a) (cat "" a))) (def string (fn (a) (cat "" a)))
(struct Alias (name value)) (struct Alias (name value))
@ -52,6 +45,13 @@
(if (iserr match) text match.value) (if (iserr match) text match.value)
))) )))
(def hour (fn (ti) (
(def h (% ti.hour 12))
(if (= 0 h) 12 h)
)))
(def zero (fn (num) (cat (if (< num 10) "0" "") num)))
(def clock (fn (ti) (cat (hour ti) ":" (zero ti.minute) ":" (zero ti.sec)))) (def clock (fn (ti) (cat (hour ti) ":" (zero ti.minute) ":" (zero ti.sec))))
(def cleanDir (fn () ( (def cleanDir (fn () (

234
src/main.c Normal file
View File

@ -0,0 +1,234 @@
#define _GNU_SOURCE
#include "pebblisp.h"
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
char* getPrompt(struct Environment* env)
{
Object prompt = fetchFromEnvironment("prompt", env);
prompt = cloneObject(prompt);
if (prompt.type == TYPE_STRING) {
char* ret = readline(prompt.string);
cleanObject(&prompt);
return ret;
}
Object param = stringFromSlice("", 1);
Object e = listEvalLambda(&prompt, &param, 2, env);
cleanObject(&prompt);
cleanObject(&param);
char* ret = readline(e.string);
cleanObject(&e);
return ret;
}
char* preprocess(char* buf, struct Environment* env)
{
Object lambda = fetchFromEnvironment("preprocess", env);
Object buffer = nullTerminated(buf);
Object s = listEvalLambda(&lambda, &buffer, 2, env);
size_t length;
return stringObj(&s, &length);
}
void repl(struct Environment* env)
{
char* buf;
using_history();
while ((buf = getPrompt(env)) != NULL) {
if (strcmp("q", buf) == 0) {
free(buf);
break;
}
buf = preprocess(buf, env);
if (buf[0] == '\0') {
free(buf);
continue;
}
add_history(buf);
if ((buf[0] == 'c' && buf[1] == 'd')) {
char* oldBuf = buf;
buf = malloc(sizeof(char) * strlen(buf + 6));
sprintf(buf, "(cd \"%s\")", oldBuf + 3);
free(oldBuf);
}
if ((buf[0] == '?' && (buf[1] == ' ' || buf[1] == '\0'))) {
char* oldBuf = buf;
buf = malloc(sizeof(char) * strlen(buf + 3));
sprintf(buf, "(%s)", oldBuf);
free(oldBuf);
}
Object o = parseEval(buf, env);
if (isFuncy(o) || isError(o, DID_NOT_FIND_SYMBOL)) {
cleanObject(&o);
system(buf);
free(buf);
continue;
}
free(buf);
size_t length;
char* output = stringObj(&o, &length);
cleanObject(&o);
printColored(output);
free(output);
printf("\n");
}
}
void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env)
{
Object args = listObject();
for (int i = 0; i < argc; i++) {
nf_addToList(&args, nullTerminated(argv[i]));
}
addToEnv(env, "args", args);
}
#ifdef __x86_64__
#include <signal.h>
#include <ucontext.h>
int nestedSegfault = 0;
void handler(int nSignum, siginfo_t* si, void* vcontext)
{
if (nestedSegfault) {
printf("Nested segfault!!!\n");
exit(139);
}
nestedSegfault = 1;
printf("Segfaulted!\n");
struct Slice* lastOpen = getLastOpen();
if (lastOpen) {
printf("line: %d\n%s\n", lastOpen->lineNumber, lastOpen->text);
} else {
printf("Happened before token processing.\n");
}
ucontext_t* context = vcontext;
context->uc_mcontext.gregs[REG_RIP]++;
exit(139);
}
void setupSegfaultHandler()
{
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = handler;
sigaction(SIGSEGV, &action, NULL);
}
#else
void setupSegfaultHandler()
{
}
#endif
struct Settings {
int runTests;
int ignoreConfig;
int ignoreLib;
int moreToDo;
const char* configFile;
} settings;
#define RUN_TESTS_ARG "--run-tests"
#define RUN_DETAILED_TESTS "=detailed"
#define IGNORE_CONFIG_ARG "--ignore-config"
#define IGNORE_LIB_ARG "--ignore-lib"
#define CONFIG_FILE_ARG "--config="
void getSettings(int argc, const char* argv[])
{
settings.runTests = 0;
settings.ignoreConfig = 0;
settings.ignoreLib = 0;
settings.moreToDo = 0;
settings.configFile = NULL;
size_t runTestsLen = strlen(RUN_TESTS_ARG);
size_t configFileLen = strlen(CONFIG_FILE_ARG);
for (int i = 1; i < argc; i++) {
if (strncmp(argv[i], RUN_TESTS_ARG, runTestsLen) == 0) {
int isDetailed = strcmp(argv[i] + runTestsLen, RUN_DETAILED_TESTS) == 0;
settings.runTests = isDetailed ? 2 : 1;
} else if (strncmp(argv[i], CONFIG_FILE_ARG, configFileLen) == 0) {
settings.configFile = argv[i] + configFileLen;
} else if (strcmp(argv[i], IGNORE_CONFIG_ARG) == 0) {
settings.ignoreConfig = 1;
} else if (strcmp(argv[i], IGNORE_LIB_ARG) == 0) {
settings.ignoreLib = 1;
} else if (argv[i][0] == '-') {
fprintf(stderr, "Unrecognized argument: '%s'\n", argv[i]);
} else if (i == (argc - 1)) {
settings.moreToDo = 1;
}
}
}
int main(int argc, const char* argv[])
{
setupSegfaultHandler();
getSettings(argc, argv);
struct Environment env = defaultEnv();
setGlobal(&env);
if (settings.runTests) {
int ret = runTests(settings.runTests == 2);
shredDictionary();
deleteEnv(global());
return ret;
}
if (!settings.ignoreLib) {
readFile(SCRIPTDIR "/lib.pbl", &env);
}
Object o = parseEval("(def prompt \"pebblisp::> \")", &env);
cleanObject(&o);
o = parseEval("(def preprocess (fn (text) (text)))", &env);
cleanObject(&o);
if (!settings.ignoreConfig) {
char config[128];
if (settings.configFile) {
sprintf(config, "%s", settings.configFile);
} else {
const char* const home = getenv("HOME");
sprintf(config, "%s/.pebblisp.pbl", home);
}
if (readFile(config, &env) == 1 && settings.configFile) {
fprintf(stderr, "Config file not found at %s\n", config);
}
}
if (settings.moreToDo) {
FILE* file = fopen(argv[argc - 1], "r");
if (file) {
// Execute a file
loadArgsIntoEnv(argc, argv, &env);
_readFile(file, &env);
} else {
// Run arguments directly as pl code
Object r = parseEval(argv[argc - 1], &env);
printAndClean(&r);
}
} else {
// Run a repl
loadArgsIntoEnv(argc, argv, &env);
repl(&env);
}
deleteEnv(&env);
shredDictionary();
// eprintf("totalSearchDepth: %d of %d searches\n", getTotalSearchDepth(), getTotalSearches());
// eprintf("\nHEAP-ALLOCATED OBJECTS: %d\n", getAllocations());
// eprintf("TOTAL OBJECT.C ALLOC: %zu\n", getBytes());
}

4
src/main.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef PEBBLISP_MAIN_H
#define PEBBLISP_MAIN_H
#endif // PEBBLISP_MAIN_H

View File

@ -1,20 +1,11 @@
#ifdef STANDALONE
#define _GNU_SOURCE
#endif
#include "pebblisp.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "tokens.h" #include "tokens.h"
#include "pebblisp.h"
#ifdef STANDALONE #ifdef STANDALONE
#include <readline/readline.h>
#include <readline/history.h>
#include "web.h" #include "web.h"
#endif #endif
@ -466,6 +457,11 @@ Result parseAtom(struct Slice* s)
struct Slice* lastOpen = NULL; struct Slice* lastOpen = NULL;
struct Slice* getLastOpen()
{
return lastOpen;
}
Object parseEval(const char* input, struct Environment* env) Object parseEval(const char* input, struct Environment* env)
{ {
struct Error err = noError(); struct Error err = noError();
@ -540,6 +536,7 @@ Object typeCheck(const char* funcName, Object* params, int length,
#ifdef STANDALONE #ifdef STANDALONE
/// Returns 1 if the file could not be opened. Otherwise, 0
int readFile(const char* filename, struct Environment* env) int readFile(const char* filename, struct Environment* env)
{ {
FILE* input = fopen(filename, "r"); FILE* input = fopen(filename, "r");
@ -592,182 +589,4 @@ int _readFile(FILE* input, struct Environment* env)
return 0; return 0;
} }
char* getPrompt(struct Environment* env) #endif // STANDALONE
{
Object prompt = fetchFromEnvironment("prompt", env);
prompt = cloneObject(prompt);
if (prompt.type == TYPE_STRING) {
char* ret = readline(prompt.string);
cleanObject(&prompt);
return ret;
}
Object param = stringFromSlice("", 1);
Object e = listEvalLambda(&prompt, &param, 2, env);
cleanObject(&prompt);
cleanObject(&param);
char* ret = readline(e.string);
cleanObject(&e);
return ret;
}
char* preprocess(char* buf, struct Environment* env)
{
Object lambda = fetchFromEnvironment("preprocess", env);
Object buffer = nullTerminated(buf);
Object s = listEvalLambda(&lambda, &buffer, 2, env);
size_t length;
return stringObj(&s, &length);
}
void repl(struct Environment* env)
{
char* buf;
using_history();
while ((buf = getPrompt(env)) != NULL) {
if (strcmp("q", buf) == 0) {
free(buf);
break;
}
buf = preprocess(buf, env);
if (buf[0] == '\0') {
free(buf);
continue;
}
add_history(buf);
if ((buf[0] == 'c' && buf[1] == 'd')) {
char* oldBuf = buf;
buf = malloc(sizeof(char) * strlen(buf + 6));
sprintf(buf, "(cd \"%s\")", oldBuf + 3);
free(oldBuf);
}
if ((buf[0] == '?' && (buf[1] == ' ' || buf[1] == '\0'))) {
char* oldBuf = buf;
buf = malloc(sizeof(char) * strlen(buf + 3));
sprintf(buf, "(%s)", oldBuf);
free(oldBuf);
}
Object o = parseEval(buf, env);
if (isFuncy(o) || isError(o, DID_NOT_FIND_SYMBOL)) {
cleanObject(&o);
system(buf);
free(buf);
continue;
}
free(buf);
size_t length;
char* output = stringObj(&o, &length);
cleanObject(&o);
printColored(output);
free(output);
printf("\n");
}
}
void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env)
{
Object args = listObject();
for (int i = 0; i < argc; i++) {
nf_addToList(&args, nullTerminated(argv[i]));
}
addToEnv(env, "args", args);
}
#ifdef __x86_64__
#include <signal.h>
#include <ucontext.h>
int nestedSegfault = 0;
void handler(int nSignum, siginfo_t* si, void* vcontext)
{
if (nestedSegfault) {
printf("Nested segfault!!!\n");
exit(139);
}
nestedSegfault = 1;
printf("Segfaulted!\n");
if (lastOpen) {
printf("line: %d\n%s\n", lastOpen->lineNumber, lastOpen->text);
} else {
printf("Happened before token processing.\n");
}
ucontext_t* context = vcontext;
context->uc_mcontext.gregs[REG_RIP]++;
exit(139);
}
void setupSegfaultHandler()
{
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = handler;
sigaction(SIGSEGV, &action, NULL);
}
#else
void setupSegfaultHandler()
{
}
#endif
// TODO: add --no-lib and --no-config and/or --config=
int main(int argc, const char* argv[])
{
setupSegfaultHandler();
const char* const home = getenv("HOME");
char config[strlen(home) + 15];
struct Environment env = defaultEnv();
setGlobal(&env);
if (argc == 2) {
const char* runTestsArg = "--run-tests";
if (strncmp(argv[1], runTestsArg, strlen(runTestsArg)) == 0) {
int ret = runTests(strcmp(argv[1] + strlen(runTestsArg), "=detailed") == 0);
shredDictionary();
deleteEnv(global());
return ret;
}
}
readFile(SCRIPTDIR "/lib.pbl", &env);
Object o = parseEval("(def prompt \"pebblisp::> \")", &env);
cleanObject(&o);
o = parseEval("(def preprocess (fn (text) (text)))", &env);
cleanObject(&o);
sprintf(config, "%s/.pebblisp.pbl", home);
readFile(config, &env);
if (argc >= 2) {
FILE* file = fopen(argv[1], "r");
if (file) {
// Execute a file
loadArgsIntoEnv(argc, argv, &env);
_readFile(file, &env);
} else {
// Run arguments directly as pl code
Object r = numberObject(0);
for (int i = 1; i < argc; i++) {
r = parseEval(argv[i], &env);
printAndClean(&r);
}
}
} else {
// Run a repl
loadArgsIntoEnv(argc, argv, &env);
repl(&env);
}
deleteEnv(&env);
shredDictionary();
// eprintf("totalSearchDepth: %d of %d searches\n", getTotalSearchDepth(), getTotalSearches());
// eprintf("\nHEAP-ALLOCATED OBJECTS: %d\n", getAllocations());
// eprintf("TOTAL OBJECT.C ALLOC: %zu\n", getBytes());
}
#endif

View File

@ -97,6 +97,8 @@ int _readFile(FILE* input, struct Environment* env);
int readFile(const char* filename, struct Environment* env); int readFile(const char* filename, struct Environment* env);
struct Slice* getLastOpen();
#endif /* STANDALONE */ #endif /* STANDALONE */
fn(mapO, "map", fn(mapO, "map",