~emersion/mrsh

fd9074d7cc205c7bf53940b59ed5eec2d5827c0a — Drew DeVault 2 years ago ee4a9ab
Initial implementation of functions

Still to come:

- I/O redirection
- Pushing argv/argc
- return
M include/shell/task.h => include/shell/task.h +1 -1
@@ 74,7 74,7 @@ struct task *task_for_clause_create(char *name, struct mrsh_array *word_list,
		struct mrsh_array *body);

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

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

M shell/task/command.c => shell/task/command.c +28 -2
@@ 11,6 11,7 @@
#include "shell/process.h"
#include "shell/shm.h"
#include "shell/task.h"
#include "shell/tasks.h"

struct task_command {
	struct task task;


@@ 19,8 20,11 @@ struct task_command {
	bool builtin;
	struct mrsh_array args;

	// only if not a builtin
	// if a process
	struct process process;
	// if a function
	struct mrsh_function *fn_def;
	struct task *fn_task;
};

static void task_command_destroy(struct task *task) {


@@ 110,6 114,25 @@ static void get_args(struct mrsh_array *args, struct mrsh_simple_command *sc,
	mrsh_array_add(args, NULL);
}

static bool task_function_start(struct task_command *tc, struct context *ctx) {
	// TODO: Push new $@/$#
	tc->fn_task = task_for_command(tc->fn_def->body);
	return tc->fn_task != NULL;
}

static int task_function_poll(struct task *task, struct context *ctx) {
	struct task_command *tc = (struct task_command *)task;

	if (!tc->started) {
		if (!task_function_start(tc, ctx)) {
			return TASK_STATUS_ERROR;
		}
		tc->started = true;
	}

	return task_poll(tc->fn_task, ctx);
}

static int task_builtin_poll(struct task *task, struct context *ctx) {
	struct task_command *tc = (struct task_command *)task;



@@ 271,9 294,12 @@ static int task_command_poll(struct task *task, struct context *ctx) {
		get_args(&tc->args, sc, ctx);
		const char *argv_0 = (char *)tc->args.data[0];
		tc->builtin = mrsh_has_builtin(argv_0);
		tc->fn_def = mrsh_hashtable_get(&ctx->state->functions, argv_0);
	}

	if (tc->builtin) {
	if (tc->fn_def) {
		return task_function_poll(task, ctx);
	} else if (tc->builtin) {
		return task_builtin_poll(task, ctx);
	} else {
		return task_process_poll(task, ctx);

M shell/task/function_definition.c => shell/task/function_definition.c +3 -4
@@ 5,14 5,13 @@

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

static void task_function_definition_destroy(struct task *task) {
	struct task_function_definition *tfn =
		(struct task_function_definition *)task;
	free(tfn->name);
	free(tfn);
}



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


@@ 36,7 35,7 @@ static const struct task_interface task_function_definition_impl = {
};

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

A test/function.sh => test/function.sh +29 -0
@@ 0,0 1,29 @@
#!/bin/sh -e
func_a() {
	echo func_a
}

func_b() {
	echo func_b
}

func_b() {
	echo func_b revised
}

func_c() {
	echo func_c

	func_c() {
		echo func_c revised
	}
}

func_a
func_b
func_c
func_c

output=$(func_a)

[ "$output" = "func_a" ]

M test/meson.build => test/meson.build +1 -0
@@ 8,6 8,7 @@ test_files = [
	'subshell.sh',
	'word.sh',
	'for.sh',
	'function.sh',
]

foreach test_file : test_files