~emersion/mrsh

199fc075860d3984d441b52e71ed66b353967102 — Johannes Altmanninger 3 years ago ad8a6ed
Implement for loop
M include/shell/task.h => include/shell/task.h +3 -0
@@ 70,6 70,9 @@ struct task *task_if_clause_create(struct task *condition, struct task *body,
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_pipeline_create(void);
void task_pipeline_add(struct task *task, struct task *child);


M include/shell/tasks.h => include/shell/tasks.h +1 -0
@@ 11,6 11,7 @@ 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_pipeline(struct mrsh_pipeline *pl);
struct task *task_for_binop(struct mrsh_binop *binop);
struct task *task_for_node(struct mrsh_node *node);

M meson.build => meson.build +1 -0
@@ 66,6 66,7 @@ lib_mrsh = library(
		'shell/task/if_clause.c',
		'shell/task/list.c',
		'shell/task/loop_clause.c',
		'shell/task/for_clause.c',
		'shell/task/pipeline.c',
		'shell/task/subshell.c',
		'shell/task/task.c',

A shell/task/for_clause.c => shell/task/for_clause.c +82 -0
@@ 0,0 1,82 @@
#define _POSIX_C_SOURCE 200809L
#include "shell/task.h"
#include "shell/tasks.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

struct task_for_clause {
	struct task task;
	struct {
		char *name;
		struct mrsh_array *word_list, *body;
	} ast;
	struct {
		struct task *word, *body;
	} tasks;
	size_t index;
	int last_body_status;
};

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

static int task_for_clause_poll(struct task *task, struct context *ctx) {
	struct task_for_clause *tfc = (struct task_for_clause *)task;
	while (true) {
		if (tfc->tasks.body) {
			/* wait for body */
			int body_status = task_poll(tfc->tasks.body, ctx);
			if (body_status < 0) {
				return body_status;
			}
			task_destroy(tfc->tasks.body);
			tfc->tasks.body = NULL;
		} else if (tfc->tasks.word) {
			/* wait for word */
			int word_status = task_poll(tfc->tasks.word, ctx);
			if (word_status < 0) {
				return word_status;
			}
			struct mrsh_word_string *word = (struct mrsh_word_string *)
				tfc->ast.word_list -> data[tfc->index - 1];
			char *value = strdup(word->str);
			mrsh_env_set(ctx->state, tfc->ast.name, value,
				MRSH_VAR_ATTRIB_NONE);
			task_destroy(tfc->tasks.word);
			tfc->tasks.word = NULL;
			tfc->tasks.body =
				task_for_command_list_array(tfc->ast.body);
		} else {
			/* create a new word */
			if (tfc->index == tfc->ast.word_list->len) {
				return 0;
			}
			struct mrsh_word **word_ptr =
				(struct mrsh_word **)&tfc->ast.word_list
					->data[tfc->index++];
			tfc->tasks.word = task_word_create(
				word_ptr, TILDE_EXPANSION_NAME);
		}
	}
}

static const struct task_interface task_for_clause_impl = {
	.destroy = task_for_clause_destroy,
	.poll = task_for_clause_poll,
};

struct task *task_for_clause_create(char *name, struct mrsh_array *word_list,
		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;
	tfc->ast.word_list = word_list;
	tfc->ast.body = body;
	tfc->index = 0;
	return &tfc->task;
}

M shell/tasks.c => shell/tasks.c +7 -1
@@ 86,6 86,10 @@ struct task *task_for_loop_clause(struct mrsh_loop_clause *lc) {
			lc->type == MRSH_LOOP_UNTIL);
}

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

struct task *task_for_command(struct mrsh_command *cmd) {
	switch (cmd->type) {
	case MRSH_SIMPLE_COMMAND:;


@@ 103,7 107,9 @@ struct task *task_for_command(struct mrsh_command *cmd) {
	case MRSH_LOOP_CLAUSE:;
		struct mrsh_loop_clause *lc = mrsh_command_get_loop_clause(cmd);
		return task_for_loop_clause(lc);
	case MRSH_FOR_CLAUSE:
	case MRSH_FOR_CLAUSE:;
		struct mrsh_for_clause *fc = mrsh_command_get_for_clause(cmd);
		return task_for_for_clause(fc);
	case MRSH_CASE_CLAUSE:
	case MRSH_FUNCTION_DEFINITION:
		assert(false); // TODO: implement this

A test/for.sh => test/for.sh +13 -0
@@ 0,0 1,13 @@
#!/bin/sh

two=2

for i in 1 $two 3; do
	echo $i
done
echo $i

for i; do
	echo
done
echo $i

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

foreach test_file : test_files