Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Added whcl decl {varname val var2 val...} syntax. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
408488e99ad6d2f494a3414cbf83d3ab |
User & Date: | stephan 2022-04-13 08:05:14 |
Context
2022-04-13
| ||
08:07 | Annotated a TODO. check-in: 3da74f5b97 user: stephan tags: trunk | |
08:05 | Added whcl decl {varname val var2 val...} syntax. check-in: 408488e99a user: stephan tags: trunk | |
07:58 | Moved the cwal index.md. check-in: ee67cc2e22 user: stephan tags: trunk | |
Changes
Changes to whcl/manual/builtins.md.
︙ | ︙ | |||
200 201 202 203 204 205 206 | that it accepts as few as one arguments, the intent of that use case being to convert non-strings to strings. <a id='bic-const'></a> const ------------------------------------------------------------ | > > | > | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | that it accepts as few as one arguments, the intent of that use case being to convert non-strings to strings. <a id='bic-const'></a> const ------------------------------------------------------------ Usages: - `const varName value|builtin command...` - `const {varName value var2 value...}` This is a convenience form of [`decl -const`](#bic-decl). <a id='bic-continue'></a> continue ------------------------------------------------------------ |
︙ | ︙ | |||
244 245 246 247 248 249 250 | <a id='bic-decl'></a> decl ------------------------------------------------------------ See also: [variables][] and [`const`](#bic-const) | > > | > | > > | | > > > > | > | | | | | | | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | <a id='bic-decl'></a> decl ------------------------------------------------------------ See also: [variables][] and [`const`](#bic-const) Usages: - `decl: [-const] varname [value|builtin-command args...]` - `decl: [-const] {varname value [var2 value2...]}` Declares a symbolic name as being available for this scope and [all subsequent sub-scopes which can see into this one](symbol-resolution.md). With the first usage, if the final argument is the name of a builtin command then that command is run, passing on any remaining arguments. That permits declarations to use (e.g.) the `object`, `array`, and `proc` commands without having to wrap them in `[...]`. The `{...}` usage requires matching pairs of var names and values and does not support commands as values unless they're wrapped in `[...]`. The first form evaluates to the new value, or `undefined` if no value was provided. The second form evaluates to `undefined`. The `-const` flag marks the variable(s) as "constant," meaning it/they cannot be reassigned. It is illegal to use this flag without providing a value. If the value is a container object, constness does not protect its contents from being modified. > Sidebar: long story short, the requirement of explicitly declaring variables instead of using `set` to both declare and assign to variables is due to significant difference between how TCL and our scripting engine handle scopes and resolve symbols. We cannot sensibly support TCL-like usage within this framework. <a id='bic-decr'></a> decr ------------------------------------------------------------ Usage: `decr identifier|$var[property] [value=1]` |
︙ | ︙ |
Changes to whcl/manual/index.md.
︙ | ︙ | |||
10 11 12 13 14 15 16 | -------- Other docs: - [Building whcl](build.md) - [Grammar](grammar.md) - [Symbol Resolution](symbol-resolution.md). | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | -------- Other docs: - [Building whcl](build.md) - [Grammar](grammar.md) - [Symbol Resolution](symbol-resolution.md). - [Data Types](type-intro.md) - [Builtin Commands and Values](builtins.md) - [API Index](api-index.md) - [whclsh: the whcl shell](whclsh.md) - [Example scripts](/dir/whcl/unit?ci=trunk) (whcl's own unit tests) - [Tips and Tricks](tips-tricks.md) for getting the most out of whcl - [Tokenization and Evaluation Models](t10n.md) |
︙ | ︙ |
Changes to whcl/manual/variables.md.
︙ | ︙ | |||
46 47 48 49 50 51 52 | To be written more succintly as: ```whcl decl o object a b c d ``` | > > > > > > > > > > > > > > > > | | < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | To be written more succintly as: ```whcl decl o object a b c d ``` > Sidebar: see [this section](builtins.md#builtin-vs-non) for why `decl` can treat builtins specially in this regard but cannot do the same for non-builtin commands. When declaring multiple values, this alternate syntax may be simpler: ```whcl decl { X 1 Y 2 } ``` Noting that that syntax does _not_ support commands (builtin or otherwise) as values unless they're wrapped in `[...]`. The "simple" form of `decl` evaluates to the value it sets, so: ```whcl assert 1 == [decl x 1] ``` The `{...}` syntax always evaluates to `undefined`. <a id='dereference'></a> Dereferencing Variables ============================================================ To "dereference" a variable means to extract its referenced value. |
︙ | ︙ |
Changes to whcl/unit/000-000-basics.whcl.
︙ | ︙ | |||
12 13 14 15 16 17 18 | abc def }}} == {abc def} assert <<<:XX three spaces XX == " three spaces " assert {{{: three spaces }}} == " three spaces " | | > > > > > | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | abc def }}} == {abc def} assert <<<:XX three spaces XX == " three spaces " assert {{{: three spaces }}} == " three spaces " decl { x 1 y 2 } assert [info is-local x] assert $x == 1 assert [info is-local y] assert 2 == $y unset x y assert ![info is-local x] decl x object {a 1 b 2 c 3} assert 1 == $x[a] assert 2 == $x[b] assert 3 == $x[c] unset \ |
︙ | ︙ |
Changes to whcl/whcl.c.
︙ | ︙ | |||
443 444 445 446 447 448 449 | #define whcl__rescopeS(S,v) \ cwal_value_rescope(&S->cs, v) #define whcl__rescopeE(E,v) \ whcl__rescopeS(E->scopes.current, v) cwal_value * whcl_scope_props(whcl_engine * const el, | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | #define whcl__rescopeS(S,v) \ cwal_value_rescope(&S->cs, v) #define whcl__rescopeE(E,v) \ whcl__rescopeS(E->scopes.current, v) cwal_value * whcl_scope_props(whcl_engine * const el, whcl_scope * const sc_){ whcl_scope * const sc = sc_ ? sc_ : whcl__scope_current(el); if(!sc->props){ sc->props = cwal_new_object_value(el->ec); if(!sc->props){WHCL__WARN_OOM; return NULL;} whcl__rescopeS(sc, sc->props); cwal_value_make_vacuum_proof(sc->props, true); cwal_value_prototype_set(sc->props, NULL); |
︙ | ︙ | |||
2404 2405 2406 2407 2408 2409 2410 | //whcl__dump_stok(ct, tok, "key"); switch(tok->ttype){ case TOK1_T_BraceGroup: case TOK1_T_IdentifierDeref: case TOK1_T_ParenGroup: rc = whcl__eval_token(el, ct, tok, 0, &key); break; | | | > > | > | > > | 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | //whcl__dump_stok(ct, tok, "key"); switch(tok->ttype){ case TOK1_T_BraceGroup: case TOK1_T_IdentifierDeref: case TOK1_T_ParenGroup: rc = whcl__eval_token(el, ct, tok, 0, &key); break; case TOK1_T_BIV: case TOK1_T_Identifier: if(tok->subscriptId) goto not_a_key; CWAL_SWITCH_FALL_THROUGH; case TOK1_T_BIC: case TOK1_T_LiteralNumber: case TOK1_T_QuotedString: case TOK1_T_SquigglyGroup: rc = whcl__create_value2(el, ct, tok, true, &key); break; default: not_a_key: rc = whcl__throw(el, ct, tok, CWAL_RC_TYPE, "Invalid token type (%s) for object key.", tok->subscriptId ? "property access" : tok1_t_cstr(tok->ttype)); break; } if(rc || (rc = whcl__holder_push(el, key))) break; if((rc = next_t)) break; //whcl__dump_stok(ct, tok, "val"); #undef next_t switch(whcl_t_is_eox(tok->ttype) ? 0 : tok->ttype){ |
︙ | ︙ | |||
3164 3165 3166 3167 3168 3169 3170 | whcl_stoken_cstr(args->ct, tArg, NULL, false)); goto end; } assert(foundIn); break; default: whcl__script_errtoken_set(args->ct, tArg); | | | | | > | 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 | whcl_stoken_cstr(args->ct, tArg, NULL, false)); goto end; } assert(foundIn); break; default: whcl__script_errtoken_set(args->ct, tArg); rc = whcl_err_throw(args->el, CWAL_RC_TYPE, "Invalid token type (%s) for '%s' command key.", tok1_t_cstr(tArg->ttype), bic->name); goto end; } assert(0==rc); if(!crv){ crv = cwal_new_integer(args->el->ec, 1)/*does not allocate/cannot fail*/; } rc = whcl__values_addsub(args->el, TOK1_T_BIC_incr==bic->ttype, value, crv, &newV); |
︙ | ︙ | |||
3194 3195 3196 3197 3198 3199 3200 | } end: if(lhs) whcl__dotop_set(args->el, NULL, NULL, NULL); whcl__holder_truncate(args->el, holdLen, NULL); return rc; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 | } end: if(lhs) whcl__dotop_set(args->el, NULL, NULL, NULL); whcl__holder_truncate(args->el, holdLen, NULL); return rc; } /** Helper for `decl`: decl [-const] { key val key val... } Resolves to `undefined`. TODO: - Add support for `set` as well. That requires a few changes, e.g. the ability to have x.y as a key. The 4th arg must be true for decl and false for set. - Consider adding support for commands in the value positions, consuming until EOL/EOF. Returns blah blah blah and ownership is blah blah blah. You know the drill. */ static int whcl__decl_read_object(whcl_engine * const el, whcl_script * ct, whcl_stoken const * tok, bool isDecl, bool isConst){ int rc = 0; cwal_size_t const holdLen = whcl__holder_len(el); whcl_script * const oldScript = el->ct; whcl_scope * const scel = whcl__scope_current(el); cwal_value * const props = whcl_scope_props(el, scel); whcl_script sub = whcl__script_empty; assert(TOK1_T_SquigglyGroup == tok->ttype); if(!props) return CWAL_RC_OOM; whcl__stoken_set(ct, tok); rc = whcl__script_sub_from_group(ct, &sub, true); if(rc) return rc; el->ct = ct; ct = ⊂ /* Process the object as a list of key/value pairs... */ #define next_t whcl__next_token_no_eol(ct, &tok) for(int i = 0; true; ++i ){ cwal_value * key = NULL; cwal_value * val = NULL; whcl_stoken const * tKey; rc = next_t; if(rc || whcl_t_is_eox(tok->ttype)) break; cwal_size_t const preKeyLen = whcl__holder_len(el); switch(tok->ttype){ #if 0 /* TODO: allow for `set` but not `decl`: */ case TOK1_T_BraceGroup: case TOK1_T_IdentifierDeref: case TOK1_T_ParenGroup: rc = whcl__eval_token(el, ct, tok, 0, &key); break; case TOK1_T_LiteralNumber: case TOK1_T_QuotedString: case TOK1_T_SquigglyGroup: #endif case TOK1_T_BIV: case TOK1_T_Identifier: if(tok->subscriptId) goto not_a_key; CWAL_SWITCH_FALL_THROUGH; case TOK1_T_BIC: rc = whcl__create_value2(el, ct, tok, true, &key); break; /* TODO: handle keys with subscriptId (property access) for isDecl==false (SET but not DECL). */ default: not_a_key: rc = whcl__throw(el, ct, tok, CWAL_RC_TYPE, "Invalid token type (%s) for a `%s` key.", tok->subscriptId ? "property access" : tok1_t_cstr(tok->ttype), isDecl ? "decl" : "set"); break; } if(rc || (rc = whcl__holder_push(el, key))) break; cwal_type_id const keyTypeID = cwal_value_type_id(key); switch(keyTypeID){ case CWAL_TYPE_STRING: break; default: rc = whcl__throw(el, ct, tok, CWAL_RC_TYPE, "Invalid type (%s) for var name.", cwal_type_id_name(keyTypeID)); break; } tKey = tok; if(rc || (rc = next_t)) break; #undef next_t switch(whcl_t_is_eox(tok->ttype) ? 0 : tok->ttype){ case 0: rc = whcl_err_throw(el, CWAL_SCR_SYNTAX, "Expecting matching key/value pairs."); /* We "could" simply default to undefined for the final value when isDecl==true but that seems likely to lead to silent misuse and downstream confusion. */ break; default: rc = whcl__eval_token(el, ct, tok, 0, &val); if(0==rc && !val) val = cwal_value_undefined(); break; } if(rc || (rc = whcl__holder_push(el, val))) break; whcl__script_errtoken_set(ct, tok); if(isDecl && whcl_get_v(el, props, key)){ cwal_size_t nKey = 0; char const * zKey = cwal_value_get_cstr(key, &nKey); rc = whcl__throw(el, ct, tKey, CWAL_RC_ALREADY_EXISTS, "Already declared in this scope: %.*s", (int)nKey, zKey); break; } cwal_ref(key); cwal_ref(val); rc = whcl_set_with_flags_v(el, props, key, val ? val : cwal_value_undefined(), isConst ? CWAL_VAR_F_CONST : 0); cwal_unref(key); cwal_unref(val); whcl__holder_truncate(el, preKeyLen, NULL); if(rc) break; } whcl__script_finalize(&sub); el->ct = oldScript; whcl__holder_truncate(el, holdLen, NULL); return rc; } /** Handler for the decl command: - `decl [-const] name [value]|builtin command` Noting that: - `-const` requires a value. Result value is that of the declared value (defaulting to the undefined value). */ static int whcl__bic_f_decl(whcl__bic const * const bic, whcl__args const * const args, cwal_value **rv){ |
︙ | ︙ | |||
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 | goto end; } /* i wonder if it might be interesting to add -unique and create a unique value with an optional wrapped value. */ } if((rc = whcl__args_ncheck(args, ndx, 1 + doConst))) goto end; tName = args->argv[ndx++]; whcl__stoken_set(args->ct, tName); if(whcl__ttype_is_biv(tName->ttype)){ //whcl__biv_search_t(args->ct, tName)){ | > > > > > > > > > | | | | | | | | | | 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 | goto end; } /* i wonder if it might be interesting to add -unique and create a unique value with an optional wrapped value. */ } if((rc = whcl__args_ncheck(args, ndx, 1 + doConst))) goto end; tName = args->argv[ndx++]; if(TOK1_T_SquigglyGroup==tName->ttype){ if(args->argv[ndx]){ rc = whcl__throw(el, args->ct, args->argv[ndx], CWAL_SCR_SYNTAX, "Extra arguments after {...}."); goto end; } rc = whcl__decl_read_object(args->el, args->ct, tName, true, doConst); goto end; } whcl__stoken_set(args->ct, tName); if(whcl__ttype_is_biv(tName->ttype)){ //whcl__biv_search_t(args->ct, tName)){ rc = whcl__throw(el, args->ct, tName, CWAL_RC_ALREADY_EXISTS, "Variable name collides with a " "builtin value: %.*s", (int)tName->length, whcl_stoken_cstr(args->ct, tName, NULL, false)); goto end; }else if(TOK1_T_Identifier!=tName->ttype){ rc = whcl__throw(el, args->ct, tName, CWAL_RC_MISUSE, "Invalid variable name: %.*s", (int)tName->length, whcl_stoken_cstr(args->ct, tName, NULL, false)); goto end; } if(ndx==args->argc) xv = cwal_value_undefined(); /* If we have a BIC, call it. This is primarily a convenience to enable: decl x proc {} ... Instead of: decl x [proc ...] |
︙ | ︙ | |||
4606 4607 4608 4609 4610 4611 4612 | "[-noscope] [varname] {body}"}, {"concat", T(concat), 1, -1, BIC(concat), "[args...]"}, {"const", T(const), 2, -1, BIC(decl), "varname value...|builtin-command args..."}, {"continue", T(continue), 0, 0, BIC(brc), ""}, {"__debug", T(__debug), 1, 1, BIC(eval), "{code block}"}, {"decl", T(decl), 1, -1, BIC(decl), | | | > | 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 | "[-noscope] [varname] {body}"}, {"concat", T(concat), 1, -1, BIC(concat), "[args...]"}, {"const", T(const), 2, -1, BIC(decl), "varname value...|builtin-command args..."}, {"continue", T(continue), 0, 0, BIC(brc), ""}, {"__debug", T(__debug), 1, 1, BIC(eval), "{code block}"}, {"decl", T(decl), 1, -1, BIC(decl), "[-const] varname [value...|builtin-command args...] " "| {varName value var2 value...}" }, {"decr", T(decr), 1, 2, BIC(crement), "varname|deref[key] [by-value]"}, {"define", T(define), 2, 2, DUMMY, "identifier value"}, {"do", T(do), 3, 3, BIC(dowhile), "{BODY} while {EXPR}"}, {"echo", T(echo), 0, -1, BIC(echo), "[-n] [args...]"}, {"eval", T(eval), 1, 3, BIC(eval), |
︙ | ︙ |