added @pragma rwpipe
All checks were successful
continuous-integration/drone/push Build is passing

changed || to |& for bidirectional piping
This commit is contained in:
2025-10-04 01:39:25 +09:00
parent 203a0660ef
commit 2bc122f23a
11 changed files with 104 additions and 59 deletions

View File

@ -1350,12 +1350,16 @@ BEGIN {
} }
``` ```
## Positional variable expression ### Positional variable expression
There are subtle differences in handling expressions for positional variables. In Hawk, many of the ambiguity issues can be resolved by enclosing the expression in parentheses. There are subtle differences in handling expressions for positional variables. In Hawk, many of the ambiguity issues can be resolved by enclosing the expression in parentheses.
| Expression | Hawk | AWK | | Expression | Hawk | AWK |
|--------------|---------------|-----------------| |--------------|---------------|-----------------|
| `$++$++i` | syntax error | OK | | `$++$++i` | syntax error | OK |
| `$(++$(++i))`| OK | syntax error | | `$(++$(++i))`| OK | syntax error |
### Return value of getline
### Others
- `return` is allowed in `BEGIN` blocks, `END` blocks, and pattern-action blocks.

View File

@ -352,12 +352,12 @@ static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
HAWK_ASSERT (a0 != HAWK_NULL); HAWK_ASSERT (a0 != HAWK_NULL);
name = hawk_rtx_getvaloocstr(rtx, a0, &len); name = hawk_rtx_getvaloocstr(rtx, a0, &len);
if (!name) return -1; if (HAWK_UNLIKELY(!name)) return -1;
if (a1) if (a1)
{ {
opt = hawk_rtx_getvaloocstr(rtx, a1, &optlen); opt = hawk_rtx_getvaloocstr(rtx, a1, &optlen);
if (!opt) if (HAWK_UNLIKELY(!opt))
{ {
hawk_rtx_freevaloocstr(rtx, a0, name); hawk_rtx_freevaloocstr(rtx, a0, name);
return -1; return -1;
@ -391,6 +391,19 @@ static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
if (opt) if (opt)
{ {
/* r and w are the input and the output from the child process perspective
* to and from are the intput and the output in terms of main process */
if (hawk_comp_oochars_oocstr(opt, optlen, HAWK_T("to"), 0) == 0)
{
optlen = 1;
opt[0] = 'r'; /* close the input to the pipe */
}
else if (hawk_comp_oochars_oocstr(opt, optlen, HAWK_T("from"), 0) == 0)
{
optlen = 1;
opt[0] = 'w'; /* close the output from the pipe */
}
if (optlen != 1 || (opt[0] != HAWK_T('r') && opt[0] != HAWK_T('w'))) if (optlen != 1 || (opt[0] != HAWK_T('r') && opt[0] != HAWK_T('w')))
{ {
n = -1; n = -1;

View File

@ -418,7 +418,7 @@ void hawk_clear (hawk_t* hawk)
hawk->parse.depth.loop = 0; hawk->parse.depth.loop = 0;
hawk->parse.depth.expr = 0; hawk->parse.depth.expr = 0;
hawk->parse.depth.incl = 0; hawk->parse.depth.incl = 0;
hawk->parse.pragma.trait = (hawk->opt.trait & (HAWK_IMPLICIT | HAWK_MULTILINESTR | HAWK_STRIPRECSPC | HAWK_STRIPSTRSPC)); /* implicit on if you didn't mask it off in hawk->opt.trait with hawk_setopt */ hawk->parse.pragma.trait = (hawk->opt.trait & (HAWK_IMPLICIT | HAWK_MULTILINESTR | HAWK_RWPIPE | HAWK_STRIPRECSPC | HAWK_STRIPSTRSPC)); /* implicit on if you didn't mask it off in hawk->opt.trait with hawk_setopt */
hawk->parse.pragma.rtx_stack_limit = 0; hawk->parse.pragma.rtx_stack_limit = 0;
hawk->parse.pragma.entry[0] = '\0'; hawk->parse.pragma.entry[0] = '\0';
@ -549,7 +549,6 @@ int hawk_setopt (hawk_t* hawk, hawk_opt_t id, const void* value)
case HAWK_OPT_LOG_MAXCAPA: case HAWK_OPT_LOG_MAXCAPA:
hawk->opt.log_maxcapa = *(hawk_oow_t*)value; hawk->opt.log_maxcapa = *(hawk_oow_t*)value;
return 0; return 0;
} }
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EINVAL); hawk_seterrnum(hawk, HAWK_NULL, HAWK_EINVAL);

View File

@ -69,8 +69,8 @@ enum tok_t
TOK_MOD_ASSN, TOK_MOD_ASSN,
TOK_EXP_ASSN, /* ^ - exponentiation */ TOK_EXP_ASSN, /* ^ - exponentiation */
TOK_CONCAT_ASSN, TOK_CONCAT_ASSN,
TOK_RS_ASSN, TOK_RS_ASSN, /* >> */
TOK_LS_ASSN, TOK_LS_ASSN, /* << */
TOK_BAND_ASSN, TOK_BAND_ASSN,
TOK_BXOR_ASSN, TOK_BXOR_ASSN,
TOK_BOR_ASSN, TOK_BOR_ASSN,
@ -95,11 +95,12 @@ enum tok_t
TOK_DIV, TOK_DIV,
TOK_IDIV, TOK_IDIV,
TOK_MOD, TOK_MOD,
TOK_LOR, TOK_LOR, /* || */
TOK_LAND, TOK_LAND, /* && */
TOK_BOR, TOK_BOR, /* | */
TOK_PIPE_BD, /* |& - bidirectional pipe */
TOK_BXOR, /* ^^ - bitwise-xor */ TOK_BXOR, /* ^^ - bitwise-xor */
TOK_BAND, TOK_BAND, /* & */
TOK_RS, TOK_RS,
TOK_LS, TOK_LS,
TOK_IN, TOK_IN,
@ -1018,12 +1019,18 @@ static int parse_progunit (hawk_t* hawk)
} }
/* NOTE: trait = is an intended assignment */ /* NOTE: trait = is an intended assignment */
else if (((trait = HAWK_IMPLICIT) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("implicit"), 0) == 0) || else if (((trait = HAWK_IMPLICIT) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("implicit"), 0) == 0) ||
((trait = HAWK_MULTILINESTR) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("multilinestr"), 0) == 0)) ((trait = HAWK_MULTILINESTR) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("multilinestr"), 0) == 0) ||
((trait = HAWK_RWPIPE) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("rwpipe"), 0) == 0))
{ {
/* @pragma implicit on /* @pragma implicit on
* @pragma implicit off * @pragma implicit off
* @pragma multilinestr on * @pragma multilinestr on
* @pragma multilinestr off */ * @pragma multilinestr off
* @pragma rwpipe on
* @pragma rwpipe off
*
* The initial values of these pragmas are set in hawk_clear()
*/
hawk_oocs_t value; hawk_oocs_t value;
if (get_token(hawk) <= -1) return -1; if (get_token(hawk) <= -1) return -1;
@ -1061,6 +1068,8 @@ static int parse_progunit (hawk_t* hawk)
* @pragma numstrdetect on * @pragma numstrdetect on
* @pragma numstrdetect off * @pragma numstrdetect off
* *
* The initial values of these pragmas are set in hawk_clear()
*
* Take note the global STRIPRECSPC is available for context based change. * Take note the global STRIPRECSPC is available for context based change.
* STRIPRECSPC takes precedence over this pragma. * STRIPRECSPC takes precedence over this pragma.
*/ */
@ -1272,7 +1281,7 @@ static int parse_progunit (hawk_t* hawk)
{ {
/* 'ptn' has been added to the chain. /* 'ptn' has been added to the chain.
* it doesn't have to be cleared here * it doesn't have to be cleared here
* as hawk_clear does it */ * as hawk_clear() does it */
/*hawk_clrpt(hawk, ptn);*/ /*hawk_clrpt(hawk, ptn);*/
return -1; return -1;
} }
@ -3290,7 +3299,7 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc)
type = (hawk->ptok.type == TOK_PRINT)? HAWK_NDE_PRINT: HAWK_NDE_PRINTF; type = (hawk->ptok.type == TOK_PRINT)? HAWK_NDE_PRINT: HAWK_NDE_PRINTF;
if (!MATCH_TERMINATOR(hawk) && !MATCH(hawk,TOK_GT) && if (!MATCH_TERMINATOR(hawk) && !MATCH(hawk,TOK_GT) &&
!MATCH(hawk,TOK_RS) && !MATCH(hawk,TOK_BOR) && !MATCH(hawk,TOK_LOR)) !MATCH(hawk,TOK_RS) && !MATCH(hawk,TOK_BOR) && !MATCH(hawk,TOK_PIPE_BD))
{ {
hawk_nde_t* args_tail; hawk_nde_t* args_tail;
hawk_nde_t* tail_prev; hawk_nde_t* tail_prev;
@ -3422,11 +3431,13 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc)
HAWK_OUT_PIPE, HAWK_OUT_PIPE,
0 0
}, },
/* |& doesn't oeverlap with other binary operators.
{ {
HAWK_BINOP_LOR, HAWK_BINOP_PIPE_BD,
HAWK_OUT_RWPIPE, HAWK_OUT_RWPIPE,
HAWK_RWPIPE HAWK_RWPIPE
} }
*/
}; };
for (i = 0; i < HAWK_COUNTOF(tab); i++) for (i = 0; i < HAWK_COUNTOF(tab); i++)
@ -3457,7 +3468,7 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc)
MATCH(hawk,TOK_RS)? HAWK_OUT_APFILE: MATCH(hawk,TOK_RS)? HAWK_OUT_APFILE:
MATCH(hawk,TOK_BOR)? HAWK_OUT_PIPE: MATCH(hawk,TOK_BOR)? HAWK_OUT_PIPE:
((hawk->opt.trait & HAWK_RWPIPE) && ((hawk->opt.trait & HAWK_RWPIPE) &&
MATCH(hawk,TOK_LOR))? HAWK_OUT_RWPIPE: MATCH(hawk,TOK_PIPE_BD))? HAWK_OUT_RWPIPE:
HAWK_OUT_CONSOLE; HAWK_OUT_CONSOLE;
if (out_type != HAWK_OUT_CONSOLE) if (out_type != HAWK_OUT_CONSOLE)
@ -5568,7 +5579,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc)
{ {
intype = HAWK_IN_PIPE; intype = HAWK_IN_PIPE;
} }
else if (MATCH(hawk,TOK_LOR) && (hawk->opt.trait & HAWK_RWPIPE)) else if (MATCH(hawk,TOK_PIPE_BD) && (hawk->parse.pragma.trait & HAWK_RWPIPE))
{ {
intype = HAWK_IN_RWPIPE; intype = HAWK_IN_RWPIPE;
} }
@ -5617,7 +5628,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc)
ploc = hawk->tok.loc; ploc = hawk->tok.loc;
var = parse_primary(hawk, &ploc); var = parse_primary(hawk, &ploc);
if (var == HAWK_NULL) goto oops; if (!var) goto oops;
if (!is_var(var) && var->type != HAWK_NDE_POS) if (!is_var(var) && var->type != HAWK_NDE_POS)
{ {
@ -6940,6 +6951,7 @@ static int get_symbols (hawk_t* hawk, hawk_ooci_t c, hawk_tok_t* tok)
{ HAWK_T("<<"), 2, TOK_LS, 0 }, { HAWK_T("<<"), 2, TOK_LS, 0 },
{ HAWK_T("<="), 2, TOK_LE, 0 }, { HAWK_T("<="), 2, TOK_LE, 0 },
{ HAWK_T("<"), 1, TOK_LT, 0 }, { HAWK_T("<"), 1, TOK_LT, 0 },
{ HAWK_T("|&"), 2, TOK_PIPE_BD, 0 },
{ HAWK_T("||"), 2, TOK_LOR, 0 }, { HAWK_T("||"), 2, TOK_LOR, 0 },
{ HAWK_T("|="), 2, TOK_BOR_ASSN, 0 }, { HAWK_T("|="), 2, TOK_BOR_ASSN, 0 },
{ HAWK_T("|"), 1, TOK_BOR, 0 }, { HAWK_T("|"), 1, TOK_BOR, 0 },

View File

@ -97,7 +97,7 @@ static const hawk_ooch_t* incop_str[] =
static const hawk_ooch_t* getline_inop_str[] = static const hawk_ooch_t* getline_inop_str[] =
{ {
HAWK_T("|"), HAWK_T("|"),
HAWK_T("||"), HAWK_T("|&"),
HAWK_T("<"), HAWK_T("<"),
HAWK_T("") HAWK_T("")
}; };
@ -105,7 +105,7 @@ static const hawk_ooch_t* getline_inop_str[] =
static const hawk_ooch_t* print_outop_str[] = static const hawk_ooch_t* print_outop_str[] =
{ {
HAWK_T("|"), HAWK_T("|"),
HAWK_T("||"), HAWK_T("|&"),
HAWK_T(">"), HAWK_T(">"),
HAWK_T(">>"), HAWK_T(">>"),
HAWK_T("") HAWK_T("")

View File

@ -25,7 +25,8 @@ check_ERRORS = e-001.err
EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \
journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \
bibtex-to-html.hawk bibtex-to-html.out \ bibtex-to-html.hawk bibtex-to-html.out \
fs-test.hawk fs-test.in fs-test.out fs-test.hawk fs-test.in fs-test.out \
two-way-pipe.hawk two-way-pipe.out
check_PROGRAMS = t-001 t-002 t-003 t-004 t-005 t-006 t-007 t-008 t-009 check_PROGRAMS = t-001 t-002 t-003 t-004 t-005 t-006 t-007 t-008 t-009

View File

@ -649,7 +649,8 @@ check_ERRORS = e-001.err
EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \
journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \
bibtex-to-html.hawk bibtex-to-html.out \ bibtex-to-html.hawk bibtex-to-html.out \
fs-test.hawk fs-test.in fs-test.out fs-test.hawk fs-test.in fs-test.out \
two-way-pipe.hawk two-way-pipe.out
t_001_SOURCES = t-001.c tap.h t_001_SOURCES = t-001.c tap.h
t_001_CPPFLAGS = $(CPPFLAGS_COMMON) t_001_CPPFLAGS = $(CPPFLAGS_COMMON)

View File

@ -81,6 +81,7 @@ function main()
run_test("journal-toc", "-vHTML=1", "journal-toc", 0, "journal-toc-html"); run_test("journal-toc", "-vHTML=1", "journal-toc", 0, "journal-toc-html");
run_test("bibtex-to-html", "", "journal-toc", 1, "bibtex-to-html"); run_test("bibtex-to-html", "", "journal-toc", 1, "bibtex-to-html");
run_test("fs-test", "", "fs-test", 0, "fs-test"); run_test("fs-test", "", "fs-test", 0, "fs-test");
run_test("two-way-pipe", "", @nil, 0, "two-way-pipe");
tap_end (); tap_end ();
} }

10
t/two-way-pipe.hawk Normal file
View File

@ -0,0 +1,10 @@
BEGIN {
cmd = "sort";
data = hawk::array("hello", "world", "two-way pipe", "testing");
for (i = 1; i <= length(data); i++) print data[i] |& cmd;
close(cmd, "to");
while ((cmd |& getline line) > 0) print line;
close(cmd);
}

4
t/two-way-pipe.out Normal file
View File

@ -0,0 +1,4 @@
hello
testing
two-way pipe
world