Open fcard opened 7 years ago
yay! macros rock.
How about this syntax?
GENSYM_COUNT=0
macro gensym(var) # create an unique name
GENSYM_COUNT+=1
local name<-create-ast name "__gensym_name_$GENSYM_COUNT"
return value :{local ~var=~name}
macro swap(x y) # swap the values of the given variables
gensym tmp
return code
~tmp=~x
~x=~y
~y=~tmp
a=1
b=2
swap a b
echo $a $b #> 2 1
Suggestions/criticism as always are welcome.
Explanation:
First off, macros manipulate data, not strings, so in order to avoid having users have to do all the things I did with setvar
and noshadow
in the compiler, I've come up with some syntactic sugar for returning and putting data in variables.
add(a b)
return value $(math a+b)
x<-add 1 2
echo $x #> 3
Which would translate to Bash as something like:
add() {
local a="${1}" b="${2}"
printf -v "$__return_value_add" '%s' $((${a}+${b}))
}
__return_value_add=__return_value_0 add 1 2
x=$__return_value_0
echo $x
The second bit of syntax is the code literal, :{some ~code}
, which creates and returns an AST. ~
is what I used for interpolation/substitution. (e.g. v=:{10}; x=:{echo ~v}
is equivalent to x=:{echo 10}
)
code=:{local x=~value}
would be equivalent to:
ast:make code local ''
ast:make __ast_child_0 assign 'x' $value
ast:push-child $code $__ast_child_0
return code
is a way to make returning multi-line ASTs simpler and more powscripty, otherwise it would need to be something like:
return value :{
block
~tmp=~x
~x=~y
~y=~tmp
}
The rest I imagine is straight forward:
macro m(a b c)
...
creates a macro m
that takes a
, b
, and c
as arguments, which behaves like a function, except it's executed in the compilation process as it's found.
Just to give some perspective on why manipulating data is better with printf -v
than with echo
:
add_echo() {
echo $((${1} + ${2}))
}
$ time for i in {1..50000}; do x=$(add_echo 1 2); done
real 0m58.490s
user 0m34.875s
sys 0m25.199s
$ time for i in {1..50000}; do __return_value_add=__return_value_0 add 1 2; x=$__return_value_0; done
real 0m1.157s
user 0m1.156s
sys 0m0.000s
So having syntax for this strategy of data passing would be nice in general.
Alternatively instead of another type of assignment
x<-f x y
we could have a "value substitution" syntax
x=$[f x y]
Which has a number of advantages like allowing more than one to be passed to a command and being more "shell-like", but I wonder if it wouldn't be confusing.
If this requires more discussion I will open another issue, although macros require either functionality to be easy to use.
last time I've used macros was with C (long time ago). I like your last 'value substitution'-example, it definately looks 'shell-like'. If this can speed up shellscripts, and it looks 'shell-ish': Im all for it.
An AST based compiler allows lisp-like macros to be implemented.
It would be very handy in implementing the remaining and future powscript extensions, as well as dealing with the fact that
eval
doesn't work with powscript code by introducing alternatives.yay/nay?