~emersion/mrsh

90b047730ce76f3514eb14114163b6f097fc1c2e — emersion 2 years ago 259ac6b
shell: make AST const, fix memory leaks
M include/shell/shell.h => include/shell/shell.h +2 -0
@@ 9,4 9,6 @@ struct context {
	int stdout_fileno;
};

void function_destroy(struct mrsh_function *fn);

#endif

M include/shell/task.h => include/shell/task.h +15 -21
@@ 60,32 60,18 @@ int task_run(struct task *task, struct context *ctx);
 * be mutated during expansion and substitution.
 */
struct task *task_command_create(struct mrsh_simple_command *sc);

struct task *task_list_create(void);
void task_list_add(struct task *task, struct task *child);

struct task *task_if_clause_create(struct task *condition, struct task *body,
	struct task *else_part);

struct task *task_loop_clause_create(struct mrsh_array *condition,
		struct mrsh_array *body, bool until);

struct task *task_for_clause_create(char *name, struct mrsh_array *word_list,
		struct mrsh_array *body);

struct task *task_function_definition_create(
		const char *name, struct mrsh_command *body);

struct task *task_pipeline_create(void);
void task_pipeline_add(struct task *task, struct task *child);

struct task *task_loop_clause_create(const struct mrsh_array *condition,
	const struct mrsh_array *body, bool until);
struct task *task_for_clause_create(const char *name,
	const struct mrsh_array *word_list, const struct mrsh_array *body);
struct task *task_function_definition_create(const char *name,
	const struct mrsh_command *body);
struct task *task_binop_create(enum mrsh_binop_type type,
	struct task *left, struct task *right);

struct task *task_async_create(struct task *async);

struct task *task_assignment_create(struct mrsh_array *assignments);

/**
 * Creates a task that mutates `word_ptr`, executing all substitutions. After
 * the task has finished, the word tree is guaranteed to only contain word


@@ 93,7 79,15 @@ struct task *task_assignment_create(struct mrsh_array *assignments);
 */
struct task *task_word_create(struct mrsh_word **word_ptr,
	enum tilde_expansion tilde_expansion);

struct task *task_subshell_create(struct task *subtask);

struct task *task_list_create(void);
void task_list_add(struct task *task, struct task *child);

struct task *task_pipeline_create(void);
void task_pipeline_add(struct task *task, struct task *child);

struct task *task_for_command_list_array(const struct mrsh_array *array);
struct task *task_for_command(const struct mrsh_command *cmd);

#endif

M include/shell/task_command.h => include/shell/task_command.h +8 -1
@@ 4,15 4,22 @@
#include "shell/process.h"
#include "shell/task.h"

enum task_command_type {
	TASK_COMMAND_PROCESS,
	TASK_COMMAND_BUILTIN,
	TASK_COMMAND_FUNCTION,
};

struct task_command {
	struct task task;
	struct mrsh_simple_command *sc;
	bool started;
	bool builtin;
	enum task_command_type type;
	struct mrsh_array args;

	// if a process
	struct process process;

	// if a function
	const struct mrsh_function *fn_def;
	struct task *fn_task;

D include/shell/tasks.h => include/shell/tasks.h +0 -20
@@ 1,20 0,0 @@
#ifndef _SHELL_TASKS_H
#define _SHELL_TASKS_H

#include <mrsh/ast.h>
#include "shell/task.h"

struct task *task_for_simple_command(struct mrsh_simple_command *sc);
struct task *task_for_node(struct mrsh_node *node);
struct task *task_for_command_list_array(struct mrsh_array *array);
struct task *task_for_command(struct mrsh_command *cmd);
struct task *task_for_if_clause(struct mrsh_if_clause *ic);
struct task *task_for_loop_clause(struct mrsh_loop_clause *lc);
struct task *task_for_command(struct mrsh_command *cmd);
struct task *task_for_for_loop(struct mrsh_for_clause *fc);
struct task *task_for_function_definition(struct mrsh_function_definition *fn);
struct task *task_for_pipeline(struct mrsh_pipeline *pl);
struct task *task_for_binop(struct mrsh_binop *binop);
struct task *task_for_node(struct mrsh_node *node);

#endif

M meson.build => meson.build +1 -1
@@ 64,6 64,7 @@ lib_mrsh = library(
		'shell/shell.c',
		'shell/shm.c',
		'shell/task/assignment.c',
		'shell/task/ast.c',
		'shell/task/async.c',
		'shell/task/binop.c',
		'shell/task/command_builtin.c',


@@ 79,7 80,6 @@ lib_mrsh = library(
		'shell/task/subshell.c',
		'shell/task/task.c',
		'shell/task/word.c',
		'shell/tasks.c',
		'shell/word.c',
	),
	dependencies: [rt],

M shell/shell.c => shell/shell.c +1 -2
@@ 6,7 6,6 @@
#include <unistd.h>
#include "shell/shell.h"
#include "shell/task.h"
#include "shell/tasks.h"

void mrsh_state_init(struct mrsh_state *state) {
	state->exit = -1;


@@ 34,7 33,7 @@ static void state_var_finish_iterator(const char *key, void *value,
	variable_destroy((struct mrsh_variable *)value);
}

static void function_destroy(struct mrsh_function *fn) {
void function_destroy(struct mrsh_function *fn) {
	if (!fn) {
		return;
	}

R shell/tasks.c => shell/task/ast.c +14 -12
@@ 3,7 3,6 @@
#include <unistd.h>
#include "shell/shell.h"
#include "shell/task.h"
#include "shell/tasks.h"

static struct mrsh_simple_command *copy_simple_command(
		const struct mrsh_simple_command *sc) {


@@ 20,7 19,7 @@ static void expand_assignments(struct task *task_list,
	}
}

struct task *task_for_simple_command(struct mrsh_simple_command *sc) {
static struct task *task_for_simple_command(struct mrsh_simple_command *sc) {
	struct task *task_list = task_list_create();

	if (sc->name == NULL) {


@@ 72,7 71,9 @@ struct task *task_for_simple_command(struct mrsh_simple_command *sc) {
	return task_list;
}

struct task *task_for_command_list_array(struct mrsh_array *array) {
static struct task *task_for_node(const struct mrsh_node *node);

struct task *task_for_command_list_array(const struct mrsh_array *array) {
	struct task *task_list = task_list_create();

	for (size_t i = 0; i < array->len; ++i) {


@@ 87,7 88,7 @@ struct task *task_for_command_list_array(struct mrsh_array *array) {
	return task_list;
}

struct task *task_for_if_clause(struct mrsh_if_clause *ic) {
static struct task *task_for_if_clause(const struct mrsh_if_clause *ic) {
	struct task *condition = task_for_command_list_array(&ic->condition);
	struct task *body = task_for_command_list_array(&ic->body);
	struct task *else_part = NULL;


@@ 97,20 98,21 @@ struct task *task_for_if_clause(struct mrsh_if_clause *ic) {
	return task_if_clause_create(condition, body, else_part);
}

struct task *task_for_loop_clause(struct mrsh_loop_clause *lc) {
static struct task *task_for_loop_clause(const struct mrsh_loop_clause *lc) {
	return task_loop_clause_create(&lc->condition, &lc->body,
			lc->type == MRSH_LOOP_UNTIL);
		lc->type == MRSH_LOOP_UNTIL);
}

struct task *task_for_for_clause(struct mrsh_for_clause *fc) {
static struct task *task_for_for_clause(const struct mrsh_for_clause *fc) {
	return task_for_clause_create(fc->name, &fc->word_list, &fc->body);
}

struct task *task_for_function_definition(struct mrsh_function_definition *fn) {
static struct task *task_for_function_definition(
		const struct mrsh_function_definition *fn) {
	return task_function_definition_create(fn->name, fn->body);
}

struct task *task_for_command(struct mrsh_command *cmd) {
struct task *task_for_command(const struct mrsh_command *cmd) {
	switch (cmd->type) {
	case MRSH_SIMPLE_COMMAND:;
		struct mrsh_simple_command *sc = mrsh_command_get_simple_command(cmd);


@@ 140,7 142,7 @@ struct task *task_for_command(struct mrsh_command *cmd) {
	assert(false);
}

struct task *task_for_pipeline(struct mrsh_pipeline *pl) {
static struct task *task_for_pipeline(const struct mrsh_pipeline *pl) {
	struct task *task_pipeline = task_pipeline_create();

	for (size_t i = 0; i < pl->commands.len; ++i) {


@@ 151,13 153,13 @@ struct task *task_for_pipeline(struct mrsh_pipeline *pl) {
	return task_pipeline;
}

struct task *task_for_binop(struct mrsh_binop *binop) {
static struct task *task_for_binop(const struct mrsh_binop *binop) {
	struct task *left = task_for_node(binop->left);
	struct task *right = task_for_node(binop->right);
	return task_binop_create(binop->type, left, right);
}

struct task *task_for_node(struct mrsh_node *node) {
static struct task *task_for_node(const struct mrsh_node *node) {
	switch (node->type) {
	case MRSH_NODE_PIPELINE:;
		struct mrsh_pipeline *pl = mrsh_node_get_pipeline(node);

M shell/task/command.c => shell/task/command.c +24 -7
@@ 11,8 11,15 @@ static void task_command_destroy(struct task *task) {
		free(tc->args.data[i]);
	}
	mrsh_array_finish(&tc->args);
	if (!tc->builtin) {
	switch (tc->type) {
	case TASK_COMMAND_PROCESS:
		process_finish(&tc->process);
		break;
	case TASK_COMMAND_BUILTIN:
		break;
	case TASK_COMMAND_FUNCTION:
		task_destroy(tc->fn_task);
		break;
	}
	free(tc);
}


@@ 49,16 56,26 @@ static int task_command_poll(struct task *task, struct context *ctx) {
	if (!tc->started) {
		get_args(&tc->args, sc, ctx);
		const char *argv_0 = (char *)tc->args.data[0];
		tc->builtin = mrsh_has_builtin(argv_0);

		enum task_command_type type;
		tc->fn_def = mrsh_hashtable_get(&ctx->state->functions, argv_0);
		if (tc->fn_def != NULL) {
			type = TASK_COMMAND_FUNCTION;
		} else if (mrsh_has_builtin(argv_0)) {
			type = TASK_COMMAND_BUILTIN;
		} else {
			type = TASK_COMMAND_PROCESS;
		}
		tc->type = type;
	}

	if (tc->fn_def) {
		return task_function_poll(task, ctx);
	} else if (tc->builtin) {
		return task_builtin_poll(task, ctx);
	} else {
	switch (tc->type) {
	case TASK_COMMAND_PROCESS:
		return task_process_poll(task, ctx);
	case TASK_COMMAND_BUILTIN:
		return task_builtin_poll(task, ctx);
	case TASK_COMMAND_FUNCTION:
		return task_function_poll(task, ctx);
	}
}


M shell/task/command_function.c => shell/task/command_function.c +0 -1
@@ 1,5 1,4 @@
#include "shell/task_command.h"
#include "shell/tasks.h"

static bool task_function_start(struct task_command *tc, struct context *ctx) {
	int argc = tc->args.len - 1;

M shell/task/for_clause.c => shell/task/for_clause.c +7 -8
@@ 1,6 1,5 @@
#define _POSIX_C_SOURCE 200809L
#include "shell/task.h"
#include "shell/tasks.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>


@@ 9,8 8,8 @@
struct task_for_clause {
	struct task task;
	struct {
		char *name;
		struct mrsh_array *word_list, *body;
		const char *name;
		const struct mrsh_array *word_list, *body;
	} ast;
	struct {
		struct task *word, *body;


@@ 21,6 20,7 @@ struct task_for_clause {

static void task_for_clause_destroy(struct task *task) {
	struct task_for_clause *tfc = (struct task_for_clause *)task;
	task_destroy(tfc->tasks.word);
	task_destroy(tfc->tasks.body);
	free(tfc);
}


@@ 43,7 43,7 @@ static int task_for_clause_poll(struct task *task, struct context *ctx) {
				return word_status;
			}
			struct mrsh_word_string *word = (struct mrsh_word_string *)
				tfc->ast.word_list -> data[tfc->index - 1];
				tfc->ast.word_list->data[tfc->index - 1];
			mrsh_env_set(ctx->state, tfc->ast.name, word->str,
				MRSH_VAR_ATTRIB_NONE);
			task_destroy(tfc->tasks.word);


@@ 56,8 56,7 @@ static int task_for_clause_poll(struct task *task, struct context *ctx) {
				return 0;
			}
			struct mrsh_word **word_ptr =
				(struct mrsh_word **)&tfc->ast.word_list
					->data[tfc->index++];
				(struct mrsh_word **)&tfc->ast.word_list->data[tfc->index++];
			tfc->tasks.word = task_word_create(
				word_ptr, TILDE_EXPANSION_NAME);
		}


@@ 69,8 68,8 @@ static const struct task_interface task_for_clause_impl = {
	.poll = task_for_clause_poll,
};

struct task *task_for_clause_create(char *name, struct mrsh_array *word_list,
		struct mrsh_array *body) {
struct task *task_for_clause_create(const char *name,
		const struct mrsh_array *word_list, const struct mrsh_array *body) {
	struct task_for_clause *tfc = calloc(1, sizeof(struct task_for_clause));
	task_init(&tfc->task, &task_for_clause_impl);
	tfc->ast.name = name;

M shell/task/function_definition.c => shell/task/function_definition.c +8 -11
@@ 1,12 1,11 @@
#include "shell/task.h"
#include "shell/tasks.h"
#include <mrsh/hashtable.h>
#include <stdlib.h>

struct task_function_definition {
	struct task task;
	const char *name;
	struct mrsh_command *body;
	const struct mrsh_command *body;
};

static void task_function_definition_destroy(struct task *task) {


@@ 21,11 20,9 @@ static int task_function_definition_poll(
		(struct task_function_definition *)task;
	struct mrsh_function *fn = calloc(1, sizeof(struct mrsh_function));
	fn->body = mrsh_command_copy(tfn->body);
	struct mrsh_function *oldfn = mrsh_hashtable_set(
			&ctx->state->functions, tfn->name, fn);
	if (oldfn) {
		free(oldfn);
	}
	struct mrsh_function *oldfn =
		mrsh_hashtable_set(&ctx->state->functions, tfn->name, fn);
	function_destroy(oldfn);
	return 0;
}



@@ 34,10 31,10 @@ static const struct task_interface task_function_definition_impl = {
	.poll = task_function_definition_poll,
};

struct task *task_function_definition_create(
		const char *name, struct mrsh_command *body) {
	struct task_function_definition *tfn = calloc(
			1, sizeof(struct task_function_definition));
struct task *task_function_definition_create(const char *name,
		const struct mrsh_command *body) {
	struct task_function_definition *tfn =
		calloc(1, sizeof(struct task_function_definition));
	task_init(&tfn->task, &task_function_definition_impl);
	tfn->name = name;
	tfn->body = body;

M shell/task/loop_clause.c => shell/task/loop_clause.c +3 -4
@@ 1,12 1,11 @@
#include <stdbool.h>
#include <stdlib.h>
#include "shell/task.h"
#include "shell/tasks.h"

struct task_loop_clause {
	struct task task;
	struct {
		struct mrsh_array *condition, *body;
		const struct mrsh_array *condition, *body;
	} ast;
	struct {
		struct task *condition, *body;


@@ 59,8 58,8 @@ static const struct task_interface task_loop_clause_impl = {
	.poll = task_loop_clause_poll,
};

struct task *task_loop_clause_create(struct mrsh_array *condition,
		struct mrsh_array *body, bool until) {
struct task *task_loop_clause_create(const struct mrsh_array *condition,
		const struct mrsh_array *body, bool until) {
	struct task_loop_clause *tlc = calloc(1, sizeof(struct task_loop_clause));
	task_init(&tlc->task, &task_loop_clause_impl);
	tlc->ast.condition = condition;