updated the compiler to make 'do' handling more consistent with {}
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
17550d44c5
commit
7ecb5d36ad
69
lib/comp.c
69
lib/comp.c
@ -2156,6 +2156,8 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
|
|||||||
hcl_funblk_info_t* fbi;
|
hcl_funblk_info_t* fbi;
|
||||||
hcl_cframe_t* cf;
|
hcl_cframe_t* cf;
|
||||||
|
|
||||||
|
/* called for {} after 'do' or a standalone {} */
|
||||||
|
|
||||||
if (flags & CEB_IS_BLOCK)
|
if (flags & CEB_IS_BLOCK)
|
||||||
{
|
{
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS_CONCODED(src, HCL_CONCODE_BLOCK) || HCL_CNODE_IS_ELIST_CONCODED(src, HCL_CONCODE_BLOCK));
|
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS_CONCODED(src, HCL_CONCODE_BLOCK) || HCL_CNODE_IS_ELIST_CONCODED(src, HCL_CONCODE_BLOCK));
|
||||||
@ -2166,6 +2168,7 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* called for 'do ...' */
|
||||||
cmd = HCL_CNODE_CONS_CAR(src); /* `do` itself */
|
cmd = HCL_CNODE_CONS_CAR(src); /* `do` itself */
|
||||||
/* `obj` must point to the expression list after `do` */
|
/* `obj` must point to the expression list after `do` */
|
||||||
obj = HCL_CNODE_CONS_CDR(src); /* expression list after it */
|
obj = HCL_CNODE_CONS_CDR(src); /* expression list after it */
|
||||||
@ -2189,16 +2192,20 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LANG_LIMIT_DO) /* this limitation doesn't seem really useful? or make it #pragma based? */
|
#if defined(LANG_LIMIT_DO) /* this limitation doesn't seem really useful? or make it #pragma based? */
|
||||||
if (!(flags & CEB_IS_BLOCK) && (flags & CEB_AUTO_FORGED))
|
if (!(flags & CEB_IS_BLOCK) /*&& (flags & CEB_AUTO_FORGED)*/)
|
||||||
{
|
{
|
||||||
/* `do` not explicitly enclosed in ().
|
/*
|
||||||
* e.g. do | x | { set x 20; };
|
* e.g. do | x | { set x 20; };
|
||||||
* ^
|
* ^
|
||||||
* +-- this is not allowed
|
* this is not allowed
|
||||||
|
*
|
||||||
|
* k := (do | x | { set x 20; })
|
||||||
|
* ^
|
||||||
|
* not allowed either
|
||||||
*/
|
*/
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(obj), HCL_NULL,
|
hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(obj), HCL_NULL,
|
||||||
"variable declaration disallowed in %hs context", ctxname);
|
"variable declaration disallowed in '%hs' context", ctxname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2219,19 +2226,6 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LANG_LIMIT_DO)
|
|
||||||
if (!(flags & CEB_IS_BLOCK) && (flags & CEB_AUTO_FORGED))
|
|
||||||
{
|
|
||||||
if (obj && HCL_CNODE_IS_CONS(obj) && hcl_countcnodecons(hcl, obj) != 1)
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (
|
|
||||||
hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(obj), HCL_NULL,
|
|
||||||
"more than one expression after %hs", ctxname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fbi = &hcl->c->funblk.info[hcl->c->funblk.depth];
|
fbi = &hcl->c->funblk.info[hcl->c->funblk.depth];
|
||||||
fbi->tmprlen = hcl->c->tv.s.len;
|
fbi->tmprlen = hcl->c->tv.s.len;
|
||||||
fbi->tmprcnt = hcl->c->tv.wcount;
|
fbi->tmprcnt = hcl->c->tv.wcount;
|
||||||
@ -2247,6 +2241,7 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
|
|||||||
cf = GET_SUBCFRAME(hcl);
|
cf = GET_SUBCFRAME(hcl);
|
||||||
cf->u.post_do.lvar_start = tvslen;
|
cf->u.post_do.lvar_start = tvslen;
|
||||||
cf->u.post_do.lvar_end = fbi->tmprlen;
|
cf->u.post_do.lvar_end = fbi->tmprlen;
|
||||||
|
hcl_logbfmt(hcl, HCL_LOG_STDERR, "tvslen=>%d fbi->tmprlen=>%d\n", (int)tvslen, (int)fbi->tmprlen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2258,12 +2253,25 @@ static int compile_do (hcl_t* hcl, hcl_cnode_t* xlist)
|
|||||||
#endif
|
#endif
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
/* (do
|
/*
|
||||||
* (+ 10 20)
|
* 'do' evaluates series of expressions.
|
||||||
* (* 2 30)
|
*
|
||||||
* ...
|
* do { ... }
|
||||||
* )
|
* do { ... } { ... }
|
||||||
* you can use this to combine multiple expressions to a single expression
|
* do 1 2 3
|
||||||
|
* do (printf "111\n") (printf "2222\n")
|
||||||
|
*
|
||||||
|
* while it looks like a cosmetic element, the followings show obvious difference:
|
||||||
|
* 1 2 3 ## the first element is treated as a callable element. in this case syntax error
|
||||||
|
* do 1 2 3 ## 1, 2, 3 are just evaulated in that order without 1 being treated as a callable
|
||||||
|
*
|
||||||
|
* More serious example:
|
||||||
|
* (fun(a b) { return (+ a b) }) 20 30 ## the returned value is 50
|
||||||
|
* do (fun(a b) { return (+ a b) }) 20 30 ## the returned value is 30
|
||||||
|
*
|
||||||
|
* The following two are mostly equivalent:
|
||||||
|
* do (a := 20) (b := 30)
|
||||||
|
* { a := 20; b := 30 }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(xlist));
|
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(xlist));
|
||||||
@ -2282,7 +2290,22 @@ static int compile_do_p1 (hcl_t* hcl)
|
|||||||
{
|
{
|
||||||
hcl_cframe_t* cf;
|
hcl_cframe_t* cf;
|
||||||
cf = GET_TOP_CFRAME(hcl);
|
cf = GET_TOP_CFRAME(hcl);
|
||||||
|
|
||||||
|
/* invalidate variables without shrinking the hcl->c->tv buffer.
|
||||||
|
* { | a b | }
|
||||||
|
* { | d | }
|
||||||
|
* this way, 'a' doesn't overlap with 'd' in terms of their position
|
||||||
|
* within the same function context and. however, it make 'a' invisible in
|
||||||
|
* the second block where 'd' is declared.
|
||||||
|
*
|
||||||
|
* If we shrinked the buffer instead, some extra code to initialize overlapping
|
||||||
|
* hcl->c->tv.wcount = saved_wcount (not available in the current code)
|
||||||
|
* hcl->c->tv.s.len = cf->u.post_do.lvar_start;
|
||||||
|
* variables upon entry to a block would need to be emitted. 'd' would need to
|
||||||
|
* get explicitly initialized to `nil` in the above case.
|
||||||
|
*/
|
||||||
kill_temporary_variables (hcl, cf->u.post_do.lvar_start, cf->u.post_do.lvar_end);
|
kill_temporary_variables (hcl, cf->u.post_do.lvar_start, cf->u.post_do.lvar_end);
|
||||||
|
|
||||||
POP_CFRAME (hcl);
|
POP_CFRAME (hcl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,8 @@ static struct voca_t
|
|||||||
|
|
||||||
{ 3, { '(',' ',')' /* XLIST */ } },
|
{ 3, { '(',' ',')' /* XLIST */ } },
|
||||||
{ 4, { '(',':',' ',')' /* MLIST */ } },
|
{ 4, { '(',':',' ',')' /* MLIST */ } },
|
||||||
{ 4, { '(',':','=',')' /* ALIST */ } },
|
{ 4, { '(',':','=',')' /* ALIST - x := y */ } },
|
||||||
{ 4, { '(','B','O',')' /* BLIST */ } },
|
{ 4, { '(','B','O',')' /* BLIST - x binop y */ } },
|
||||||
{ 3, { '{',' ','}' /* BLOCK */ } },
|
{ 3, { '{',' ','}' /* BLOCK */ } },
|
||||||
{ 4, { '#','[',' ',']' /* ARRAY */ } },
|
{ 4, { '#','[',' ',']' /* ARRAY */ } },
|
||||||
{ 5, { '#','b','[',' ',']' /* BYTE ARRAY */ } },
|
{ 5, { '#','b','[',' ',']' /* BYTE ARRAY */ } },
|
||||||
|
@ -16,7 +16,6 @@ check_SCRIPTS = \
|
|||||||
check_ERRORS = \
|
check_ERRORS = \
|
||||||
call-5001.err \
|
call-5001.err \
|
||||||
class-5001.err \
|
class-5001.err \
|
||||||
do-5001.err \
|
|
||||||
feed-5001.err \
|
feed-5001.err \
|
||||||
mlist-5001.err \
|
mlist-5001.err \
|
||||||
var-5001.err \
|
var-5001.err \
|
||||||
|
@ -488,7 +488,6 @@ check_SCRIPTS = \
|
|||||||
check_ERRORS = \
|
check_ERRORS = \
|
||||||
call-5001.err \
|
call-5001.err \
|
||||||
class-5001.err \
|
class-5001.err \
|
||||||
do-5001.err \
|
|
||||||
feed-5001.err \
|
feed-5001.err \
|
||||||
mlist-5001.err \
|
mlist-5001.err \
|
||||||
var-5001.err \
|
var-5001.err \
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
## if `do` is not enclosed in `( )`, variable declaration is prohibited
|
|
||||||
do { | k | set k 10 };
|
|
||||||
do | k | {set k 10;}; ##ERROR: syntax error - variable declaration disallowed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## if `do` is not enclosed in `( )`, it supports only the limited number of expressions.
|
|
||||||
|
|
||||||
do ; ## this is ok
|
|
||||||
|
|
||||||
do 1; ## this is ok
|
|
||||||
|
|
||||||
do { set k 10; printf "k=%d\n" k; } { set k 20; printf "k=%d\n" k; }; ##ERROR: syntax error - more than one expression after do
|
|
@ -194,3 +194,25 @@ throw ##ERROR: syntax error - no value or expression after 'throw'
|
|||||||
---
|
---
|
||||||
|
|
||||||
throw throw ##ERROR: syntax error - 'throw' prohibited in this context
|
throw throw ##ERROR: syntax error - 'throw' prohibited in this context
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
class X {
|
||||||
|
x := {
|
||||||
|
|a| ##ERROR: syntax error - variable declaration disallowed in class init scope
|
||||||
|
a := 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
do ; ## this is ok
|
||||||
|
do 1; ## this is ok
|
||||||
|
|
||||||
|
k := (do 1 2 3); ## ok too
|
||||||
|
## do doesn't allow variable declaration
|
||||||
|
do { | k | set k 10 };
|
||||||
|
do | k | {set k 10;}; ##ERROR: syntax error - variable declaration disallowed in 'do' context
|
||||||
|
|
||||||
|
---
|
||||||
|
k := (do | k | {set k 10;}) ##ERROR: syntax error - variable declaration disallowed in 'do' context
|
||||||
|
@ -85,8 +85,8 @@ if (nqv? R false) (print "ERROR: R is not false\n") \
|
|||||||
else (printf "OK: %O\n" R)
|
else (printf "OK: %O\n" R)
|
||||||
|
|
||||||
set v #(
|
set v #(
|
||||||
(do |a b| (set a 10) (set b 20) (+ a b) )
|
{ |a b| set a 10; set b 20; + a b }
|
||||||
(do |a b| (set a 11) (set b 21) (+ a b) )
|
{ |a b| set a 11; set b 21; + a b }
|
||||||
999
|
999
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user