diff --git a/Makefile.am b/Makefile.am index b1d54aae..4570ea91 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,7 @@ hawkgo.check: CC=$(CC) \ CGO_CFLAGS="-I$(abs_srcdir)/lib -I$(abs_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA) $(CGO_CFLAGS_ADD)" \ CGO_LDFLAGS="-L$(abs_builddir)/lib -L$(abs_builddir)/lib/.libs -lhawk -ldl $(LIBM) $(CGO_LDFLAGS_EXTRA) $(CGO_LDFLAGS_ADD)" \ - go test -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/hawkgo.bin -modfile $(abs_builddir)/go.mod + go test -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -modfile $(abs_builddir)/go.mod go clean -C $(srcdir) -x -modfile $(abs_builddir)/go.mod # fake recipes to deceive make diff --git a/Makefile.in b/Makefile.in index 9111c35e..0a9f68a3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -970,7 +970,7 @@ clean-local: @ENABLE_HAWKGO_TRUE@ CC=$(CC) \ @ENABLE_HAWKGO_TRUE@ CGO_CFLAGS="-I$(abs_srcdir)/lib -I$(abs_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA) $(CGO_CFLAGS_ADD)" \ @ENABLE_HAWKGO_TRUE@ CGO_LDFLAGS="-L$(abs_builddir)/lib -L$(abs_builddir)/lib/.libs -lhawk -ldl $(LIBM) $(CGO_LDFLAGS_EXTRA) $(CGO_LDFLAGS_ADD)" \ -@ENABLE_HAWKGO_TRUE@ go test -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/hawkgo.bin -modfile $(abs_builddir)/go.mod +@ENABLE_HAWKGO_TRUE@ go test -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -modfile $(abs_builddir)/go.mod @ENABLE_HAWKGO_TRUE@ go clean -C $(srcdir) -x -modfile $(abs_builddir)/go.mod # fake recipes to deceive make diff --git a/README.md b/README.md index 0f174381..7252cc0b 100644 --- a/README.md +++ b/README.md @@ -588,7 +588,7 @@ and represents the value of 0. ```awk BEGIN { @local x, i; - x = hawk::map(); ## you can omit this line + x = hawk::map(); ## you can omit this line or use @{} x["one"] = 1; x["two"] = 2; x[199] = 3; @@ -602,7 +602,7 @@ BEGIN { ```awk BEGIN { @local x, i - x = hawk::array() + x = hawk::array() ## you can use @[] instead of hawk::array() for (i = 0; i < 20; i++) x[i] = i; print hawk::isarray(x), hawk::ismap(x) print "--------------"; diff --git a/lib/parse.c b/lib/parse.c index 17b1ce64..fe6dd6e6 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -123,6 +123,8 @@ enum tok_t TOK_ELLIPSIS, TOK_DBLPERIOD, /* not used yet */ TOK_PERIOD, /* not used yet */ + TOK_ATBRACK, /* @[ */ + TOK_ATBRACE, /* @{ */ /* == begin reserved words == */ /* === extended reserved words === */ @@ -173,10 +175,6 @@ enum tok_t TOK_MBS, TOK_REX, TOK_XNIL, -#if 0 - TOK_HAWK_ARRAY, - TOK_HAWK_MAP, -#endif __TOKEN_COUNT__ }; @@ -249,7 +247,7 @@ static hawk_nde_t* parse_hashidx (hawk_t* hawk, const hawk_oocs_t* name, const h #define FNCALL_FLAG_NOARG (1 << 0) /* no argument */ #define FNCALL_FLAG_VAR (1 << 1) -static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc_t* fnc, const hawk_loc_t* xloc, int flags); +static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc_t* fnc, const hawk_loc_t* xloc, int flags, int closer_token); static hawk_nde_t* parse_primary_ident_segs (hawk_t* hawk, const hawk_loc_t* xloc, const hawk_oocs_t* full, const hawk_oocs_t segs[], int nsegs); @@ -585,7 +583,7 @@ static int parse (hawk_t* hawk) if (!(hawk->opt.trait & HAWK_IMPLICIT)) { /* ensure that all functions called are defined in the EXPLICIT-only mode. - * otherwise, the error detection will get delay until run-time. */ + * otherwise, the error detection will get delayed until run-time. */ hawk_htb_pair_t* p; hawk_htb_itr_t itr; @@ -597,8 +595,7 @@ static int parse (hawk_t* hawk) { hawk_nde_t* nde; - /* see parse_fncall() for what is - * stored into hawk->tree.funs */ + /* see parse_fncall() for what is stored into hawk->tree.funs */ nde = (hawk_nde_t*)HAWK_HTB_VPTR(p); hawk_seterrfmt(hawk, &nde->loc, HAWK_EFUNNF, FMT_EFUNNF, HAWK_HTB_KLEN(p), HAWK_HTB_KPTR(p)); goto oops; @@ -4900,7 +4897,7 @@ static HAWK_INLINE int isfnname (hawk_t* hawk, const hawk_oocs_t* name) return isfunname(hawk, name, HAWK_NULL); } -static hawk_nde_t* parse_primary_char (hawk_t* hawk, const hawk_loc_t* xloc) +static hawk_nde_t* parse_primary_char (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_char_t* nde; @@ -4925,7 +4922,7 @@ oops: return HAWK_NULL; } -static hawk_nde_t* parse_primary_bchr (hawk_t* hawk, const hawk_loc_t* xloc) +static hawk_nde_t* parse_primary_bchr (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_bchr_t* nde; @@ -5008,7 +5005,7 @@ oops: return HAWK_NULL; } -static hawk_nde_t* parse_primary_str (hawk_t* hawk, const hawk_loc_t* xloc) +static hawk_nde_t* parse_primary_str (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_str_t* nde; @@ -5168,6 +5165,93 @@ oops: return HAWK_NULL; } +static hawk_nde_t* _parse_primary_array_or_map (hawk_t* hawk, const hawk_loc_t* xloc, const hawk_oocs_t* full, const hawk_oocs_t segs[], int nsegs, int closer_token) +{ + /* treat it as if it's hawk::array() */ + + hawk_nde_t* nde = HAWK_NULL; + hawk_mod_t* mod; + hawk_mod_sym_t sym; + hawk_fnc_t fnc; + + mod = query_module(hawk, segs, nsegs, &sym); + if (HAWK_UNLIKELY(!mod)) + { + ADJERR_LOC(hawk, xloc); + return HAWK_NULL; + } + + if (sym.type != HAWK_MOD_FNC || ((hawk->opt.trait & sym.u.fnc_.trait) != sym.u.fnc_.trait)) + { + hawk_seterrfmt(hawk, xloc, HAWK_EUNDEF, FMT_EUNDEF, full->len, full->ptr); + return HAWK_NULL; + } + + HAWK_MEMSET (&fnc, 0, HAWK_SIZEOF(fnc)); + fnc.name.ptr = full->ptr; + fnc.name.len = full->len; + fnc.spec = sym.u.fnc_; + fnc.mod = mod; + + return parse_fncall(hawk, full, &fnc, xloc, 0, closer_token); +} + +static hawk_nde_t* parse_primary_array (hawk_t* hawk, const hawk_loc_t* xloc) +{ + /* treat it as if it's hawk::array() */ + hawk_oocs_t segs[2]; + hawk_oocs_t full; + hawk_nde_t* nde; + + segs[0].ptr = HAWK_T("hawk"); + segs[0].len = 4; + segs[1].ptr = HAWK_T("array"); + segs[1].len = 5; + + full.len = 11; + full.ptr = hawk_allocmem(hawk, HAWK_SIZEOF(*full.ptr) * 12); + if (HAWK_UNLIKELY(!full.ptr)) + { + const hawk_ooch_t* bem = hawk_backuperrmsg(hawk); + hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ENOMEM, HAWK_T("unable to allocate internal name for @[ - %js"), bem); + return HAWK_NULL; + } + + hawk_copy_oochars_to_oocstr_unlimited(&full.ptr[0], HAWK_T("hawk::array"), 11); + + nde = _parse_primary_array_or_map(hawk, xloc, &full, segs, 2, TOK_RBRACK); + if (HAWK_UNLIKELY(!nde)) hawk_freemem(hawk, full.ptr); + return nde; +} + +static hawk_nde_t* parse_primary_map (hawk_t* hawk, const hawk_loc_t* xloc) +{ + /* treat it as if it's hawk::map() */ + hawk_oocs_t segs[2]; + hawk_oocs_t full; + hawk_nde_t* nde; + + segs[0].ptr = HAWK_T("hawk"); + segs[0].len = 4; + segs[1].ptr = HAWK_T("map"); + segs[1].len = 3; + + full.len = 9; + full.ptr = hawk_allocmem(hawk, HAWK_SIZEOF(*full.ptr) * 10); + if (HAWK_UNLIKELY(!full.ptr)) + { + const hawk_ooch_t* bem = hawk_backuperrmsg(hawk); + hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ENOMEM, HAWK_T("unable to allocate internal name for @{ - %js"), bem); + return HAWK_NULL; + } + + hawk_copy_oochars_to_oocstr_unlimited(&full.ptr[0], HAWK_T("hawk::map"), 9); + + nde = _parse_primary_array_or_map(hawk, xloc, &full, segs, 2, TOK_RBRACE); + if (HAWK_UNLIKELY(!nde)) hawk_freemem(hawk, full.ptr); + return nde; +} + static hawk_nde_t* parse_primary_lparen (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_t* nde; @@ -5500,6 +5584,12 @@ static hawk_nde_t* parse_primary_nopipe (hawk_t* hawk, const hawk_loc_t* xloc) case TOK_IDENT: return parse_primary_ident(hawk, xloc); + case TOK_ATBRACK: + return parse_primary_array(hawk, xloc); + + case TOK_ATBRACE: + return parse_primary_map(hawk, xloc); + case TOK_CHAR: return parse_primary_char(hawk, xloc); @@ -5723,7 +5813,7 @@ static hawk_nde_t* parse_variable (hawk_t* hawk, const hawk_loc_t* xloc, hawk_nd #if defined(HAWK_ENABLE_FUN_AS_VALUE) if (!is_fcv) return (hawk_nde_t*)nde; - return parse_fncall(hawk, (const hawk_oocs_t*)nde, HAWK_NULL, xloc, FNCALL_FLAG_VAR); + return parse_fncall(hawk, (const hawk_oocs_t*)nde, HAWK_NULL, xloc, FNCALL_FLAG_VAR, TOK_RPAREN); #else return (hawk_nde_t*)nde; #endif @@ -5836,9 +5926,8 @@ static hawk_nde_t* parse_primary_ident_noseg (hawk_t* hawk, const hawk_loc_t* xl return parse_primary_ident_segs(hawk, xloc, name, segs, 2); } - /* fnc->dfl0 means that the function can be called without (). - * i.e. length */ - nde = parse_fncall(hawk, name, fnc, xloc, ((!MATCH(hawk,TOK_LPAREN) && fnc->dfl0)? FNCALL_FLAG_NOARG: 0)); + /* fnc->dfl0 means that the function can be called without (). e.g. length */ + nde = parse_fncall(hawk, name, fnc, xloc, ((!MATCH(hawk,TOK_LPAREN) && fnc->dfl0)? FNCALL_FLAG_NOARG: 0), TOK_RPAREN); } else { @@ -5881,7 +5970,7 @@ static hawk_nde_t* parse_primary_ident_noseg (hawk_t* hawk, const hawk_loc_t* xl { /* must be a function name */ HAWK_ASSERT(hawk_htb_search(hawk->parse.named, name->ptr, name->len) == HAWK_NULL); - nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0); + nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0, TOK_RPAREN); } else { @@ -5924,7 +6013,7 @@ static hawk_nde_t* parse_primary_ident_noseg (hawk_t* hawk, const hawk_loc_t* xl } else { - nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0); + nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0, TOK_RPAREN); } } else @@ -5962,7 +6051,7 @@ static hawk_nde_t* parse_primary_ident_noseg (hawk_t* hawk, const hawk_loc_t* xl #if defined(HAWK_ENABLE_FUN_AS_VALUE) if (is_fncall_var) - nde = parse_fncall(hawk, (const hawk_oocs_t*)nde, HAWK_NULL, xloc, FNCALL_FLAG_VAR); + nde = parse_fncall(hawk, (const hawk_oocs_t*)nde, HAWK_NULL, xloc, FNCALL_FLAG_VAR, TOK_RPAREN); #endif } } @@ -5974,7 +6063,7 @@ static hawk_nde_t* parse_primary_ident_noseg (hawk_t* hawk, const hawk_loc_t* xl { /* it is a function call as the name is followed * by ( with/without spaces and implicit variables are disabled. */ - nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0); + nde = parse_fncall(hawk, name, HAWK_NULL, xloc, 0, TOK_RPAREN); } else { @@ -6019,7 +6108,7 @@ static hawk_nde_t* parse_primary_ident_segs (hawk_t* hawk, const hawk_loc_t* xlo fnc.name.len = full->len; fnc.spec = sym.u.fnc_; fnc.mod = mod; - nde = parse_fncall(hawk, full, &fnc, xloc, 0); + nde = parse_fncall(hawk, full, &fnc, xloc, 0, TOK_RPAREN); } else { @@ -6290,7 +6379,7 @@ exit_func: return HAWK_NULL; } -static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc_t* fnc, const hawk_loc_t* xloc, int flags) +static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc_t* fnc, const hawk_loc_t* xloc, int flags, int closer_token) { hawk_nde_t* head, * curr, * nde; hawk_nde_fncall_t* call; @@ -6304,7 +6393,7 @@ static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc if (flags & FNCALL_FLAG_NOARG) goto make_node; if (get_token(hawk) <= -1) goto oops; - if (MATCH(hawk,TOK_RPAREN)) + if (MATCH(hawk, closer_token)) { /* no parameters to the function call */ if (get_token(hawk) <= -1) goto oops; @@ -6324,13 +6413,13 @@ static hawk_nde_t* parse_fncall (hawk_t* hawk, const hawk_oocs_t* name, hawk_fnc nargs++; - if (MATCH(hawk,TOK_RPAREN)) + if (MATCH(hawk, closer_token)) { if (get_token(hawk) <= -1) goto oops; break; } - if (!MATCH(hawk,TOK_COMMA)) + if (!MATCH(hawk, TOK_COMMA)) { hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ECOMMA, FMT_ECOMMA, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name)); goto oops; @@ -7121,19 +7210,16 @@ retry: GET_CHAR_TO(hawk, c); -#if 0 if (c == '[' || c == '{') /* syntatic sugar for array/map composition */ { int tt; ADD_TOKEN_CHAR(hawk, tok, '@'); ADD_TOKEN_CHAR(hawk, tok, c); - tt = (c == '['? TOK_HAWK_ARRAY: TOK_HAWK_MAP); + tt = (c == '['? TOK_ATBRACK: TOK_ATBRACE); SET_TOKEN_TYPE(hawk, tok, tt); GET_CHAR(hawk); } - else -#endif - if (c != '_' && !hawk_is_ooch_alpha(c)) + else if (c != '_' && !hawk_is_ooch_alpha(c)) { /* this extended keyword is empty, * not followed by a valid word */ diff --git a/lib/run.c b/lib/run.c index c731409f..759548b5 100644 --- a/lib/run.c +++ b/lib/run.c @@ -5028,7 +5028,7 @@ static HAWK_INLINE int __cmp_bchr_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_v { hawk_bchu_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left); hawk_oochu_t oc = v1; - return hawk_comp_oochars(&oc, 1, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase); + return hawk_comp_oochars((const hawk_ooch_t*)&oc, 1, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase); } static HAWK_INLINE int __cmp_bchr_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint) diff --git a/t/h-001.hawk b/t/h-001.hawk index 1357aae3..a7a91a8a 100644 --- a/t/h-001.hawk +++ b/t/h-001.hawk @@ -187,6 +187,16 @@ function main() tap_ensure (a[1][2], 20, @SCRIPTNAME, @SCRIPTLINE); } + { + @local a; + a = @[10, @[20, 30], 40]; + tap_ensure(a[1], 10, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure(a[2][1], 20, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure(a[2][2], 30, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure(a[3], 40, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure(length(a), 3, @SCRIPTNAME, @SCRIPTLINE); + } + { @local a, nil; a = hawk::array(); @@ -259,6 +269,11 @@ function main() c[10,20,30] = "heloo"; tap_ensure (((10,20,30) in c), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure (((10,30,30) in c), 0, @SCRIPTNAME, @SCRIPTLINE); + + + c = @{ "abc", 10, "def", 20.9 }; + tap_ensure (c["abc"], 10, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (c["def"], 20.9, @SCRIPTNAME, @SCRIPTLINE); } {