diff --git a/src/ast/ast.c b/src/ast/ast.c index 2dae1898..616e1a98 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -26,6 +26,13 @@ struct ast_node *ast_node_word(char *value) return node; } +struct ast_node *ast_node_word_double_quote(char *value) +{ + struct ast_node *node = ast_node_new(AST_WORD_DOUBLE_QUOTE); + node->value = value; + return node; +} + void ast_append(struct ast_node *parent, struct ast_node *child) { if (parent->children == NULL) diff --git a/src/ast/ast.h b/src/ast/ast.h index 0fda59fa..47babb3b 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -37,7 +37,8 @@ enum ast_type AST_OR, AST_COMMAND, AST_WORD_ASSIGNMENT, - AST_VARIABLE + AST_VARIABLE, + AST_WORD_DOUBLE_QUOTE }; /** @@ -79,6 +80,13 @@ void ast_free(struct ast_node *node); */ struct ast_node *ast_node_word(char *value); +/** + * \brief Create a new AST node of type AST_WORD_DOUBLE_QUOTE. + * \param value The value of the node. + * \return The new node. + */ +struct ast_node *ast_node_word_double_quote(char *value); + /** * \brief Convert an AST type to a string. * \param type The type to convert. diff --git a/src/execute/utils/ast_variable.c b/src/execute/utils/ast_variable.c index 79e7ba25..0c393114 100644 --- a/src/execute/utils/ast_variable.c +++ b/src/execute/utils/ast_variable.c @@ -130,7 +130,7 @@ int ast_eval_assignment(struct ast_node *node) */ char *handle_word(struct ast_node *node) { - if (node->type == AST_WORD) + if (node->type == AST_WORD || node->type == AST_WORD_DOUBLE_QUOTE) { return node->value; } diff --git a/src/execute/utils/builtin.c b/src/execute/utils/builtin.c index 4cb12a08..630e4fe5 100644 --- a/src/execute/utils/builtin.c +++ b/src/execute/utils/builtin.c @@ -67,7 +67,7 @@ void print_echo(struct ast_node *node, int enable_escapes, int j) } } if (i != node->children_count - 1 - && node->children[i]->type != AST_VARIABLE) + && node->children[i]->type != AST_VARIABLE && node->children[i]->type != AST_WORD_DOUBLE_QUOTE) putchar(' '); } } diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 89b5f2a4..0d1a9b80 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -317,7 +317,8 @@ struct token parse_input_for_tok(struct lexer *lexer) lexer->curr_tok.type = TOKEN_EOL; } // Else it's a word - token.type = TOKEN_WORD; + token.type = lexer->curr_tok.type == TOKEN_DOUBLE_QUOTE ? TOKEN_WORD_DOUBLE_QUOTE + : TOKEN_WORD; token.data = word; return token; } diff --git a/src/lexer/tests/lexer2_tests.c b/src/lexer/tests/lexer2_tests.c index 2422ef5f..93a6eee3 100644 --- a/src/lexer/tests/lexer2_tests.c +++ b/src/lexer/tests/lexer2_tests.c @@ -928,7 +928,7 @@ Test(lexer2, variable_distinction_access_double_quote_with_string) token_free(tok); tok = lexer_pop(lexer); - cr_assert_eq(tok.type, TOKEN_WORD, "got %d", tok.type); + cr_assert_eq(tok.type, TOKEN_WORD_DOUBLE_QUOTE, "got %d", tok.type); cr_assert_str_eq(tok.data, "variable:"); token_free(tok); @@ -1099,9 +1099,70 @@ Test(lexer2, personalized_variable2) token_free(tok); tok = lexer_pop(lexer); - cr_assert_eq(tok.type, TOKEN_VARIABLE); - cr_assert_str_eq(tok.data, "$a"); + cr_assert_eq(tok.type, TOKEN_VARIABLE, "got %d", tok.type); + cr_assert_str_eq(tok.data, "$a", "got %s", tok.data); token_free(tok); lexer_free(lexer); } + +Test (lexer2, double_quote_space) +{ + struct lexer *lexer = lexer_new("h=\"Hello\"; w=\"World\"; echo \"$h, ${w}!\""); + struct token tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD_ASSIGNMENT); + cr_assert_str_eq(tok.data, "h"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD); + cr_assert_str_eq(tok.data, "Hello"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_SEMICOLON); + cr_assert_str_eq(tok.data, ";"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD_ASSIGNMENT); + cr_assert_str_eq(tok.data, "w"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD); + cr_assert_str_eq(tok.data, "World"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_SEMICOLON); + cr_assert_str_eq(tok.data, ";"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD); + cr_assert_str_eq(tok.data, "echo"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_VARIABLE); + cr_assert_str_eq(tok.data, "$h"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD_DOUBLE_QUOTE); + cr_assert_str_eq(tok.data, ", "); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_VARIABLE); + cr_assert_str_eq(tok.data, "$w"); + token_free(tok); + + tok = lexer_pop(lexer); + cr_assert_eq(tok.type, TOKEN_WORD); + cr_assert_str_eq(tok.data, "!"); + token_free(tok); + + lexer_free(lexer); +} \ No newline at end of file diff --git a/src/lexer/token.h b/src/lexer/token.h index b012d561..5ef1295f 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -36,6 +36,7 @@ enum token_type TOKEN_IONUMBER, // [0-9]+ TOKEN_REDIR, // >, <, >>, >&, <&, >|, <> TOKEN_DOUBLE_QUOTE, // " + TOKEN_WORD_DOUBLE_QUOTE, // "[a-zA-Z0-9_ ]*" TOKEN_WORD_ASSIGNMENT, // variable= TOKEN_VARIABLE, // $variable diff --git a/src/parser/parser_element.c b/src/parser/parser_element.c index c8635830..4e27385c 100644 --- a/src/parser/parser_element.c +++ b/src/parser/parser_element.c @@ -159,12 +159,12 @@ struct ast_node *simple_command(struct lexer *lexer) child2 = prefix(lexer); } } - if (parser_peek(lexer) != TOKEN_WORD) + if (parser_peek(lexer) != TOKEN_WORD && parser_peek(lexer) != TOKEN_WORD_DOUBLE_QUOTE) { return current; } } - if (parser_peek(lexer) == TOKEN_WORD) + if (parser_peek(lexer) == TOKEN_WORD || parser_peek(lexer) == TOKEN_WORD_DOUBLE_QUOTE) { char *value = lexer_peek(lexer).data; if (strcmp(value, "while") == 0 || strcmp(value, "until") == 0 @@ -209,11 +209,16 @@ struct ast_node *element(struct lexer *lexer) || parser_peek(lexer) == TOKEN_WORD_ASSIGNMENT || parser_peek(lexer) == TOKEN_NEGATE) { - // printf("value=%s\n", lexer_peek(lexer).data); struct ast_node *curr = ast_node_word(lexer_peek(lexer).data); parser_pop(lexer); return curr; } + else if (parser_peek(lexer) == TOKEN_WORD_DOUBLE_QUOTE) + { + struct ast_node *curr = ast_node_word_double_quote(lexer_peek(lexer).data); + parser_pop(lexer); + return curr; + } // printf("Error: element\n"); ast_free(current); diff --git a/src/parser/tests/parser_tests.c b/src/parser/tests/parser_tests.c index dd182b27..c9951023 100644 --- a/src/parser/tests/parser_tests.c +++ b/src/parser/tests/parser_tests.c @@ -236,3 +236,12 @@ Test(parser, error4) lexer_free(lexer); ast_free(node); } + +Test(parser, custom_double_quote) +{ + struct lexer *lexer = lexer_new("echo \"variable= $a\""); + struct ast_node *node = parse(lexer); + + lexer_free(lexer); + ast_free(node); +} \ No newline at end of file