This is an old revision of the document!
Table of Contents
Metaprogramming
AT Zero - AmbientTalk without syntactic sugar
In AmbientTalk, everything is an object, also native values such as numbers, booleans, strings and tables. Hence, the only way to interact with these values is by sending messages to them. However, there are some constructs in AmbientTalk that do not seem to send a message at all. Examples are table access/assignment, control structures and arithmic operations:
>[5,6,7][2] >>6 >if: 1 == 2 then: { 13 } else: { 42 } >>42 >1 + 2 * 3 >>7
However, these constructs are all syntactic sugar. Behind the scenes, they all perform message sends. The following code shows the equivalents of the previous code, but with the actual message sends:
>[5, 6, 7].at(2) >>6 >(1 == 2).ifTrue: { 13 } ifFalse: { 42 } >>42 >1.+(2.*(3)) >>7
Another special AmbientTalk construct is the literal closure. A literal closure is just an object with a special apply method that will execute the body of the literal closure.
Quasiquoting and splicing
Qouting
Any valid AmbientTalk expression can be quoted. This prevents the expression from being evaluated. Instead, it is returned literally.
Quoting an expression is done with the `
operator. There are four variants:
`…
for quoting literal values`(…)
for quoting expressions`{…}
for quoting statement lists`[…]
for quoting tables
Literal values
Quoting a literal value such as a number or a string results in the exact same number or string.
>`3 == 3 >>true >`3 + 8 >>11 >`"text" == "text" >>true
An identifer can also be quoted. This returns a symbol object:
>foo Undefined variable access: foo >`foo >>foo >`foo.text >>"foo"
Note that in `foo.text
, the quoted expression is foo
and not foo.text
. The selection is performed on the result of the quotation, in this case a symbol.
Expressions
To quote a complete expression, it has to be wrapped in parantheses:
>`(foo.text) >>foo.text >`(foo(1, 2, 3)) >>foo(1, 2, 3) >`(1+2) >>1.+(2) >`(o.m()) >>o.m()
Statements
Statements (definitions, assignments, …) can also be quoted, but only inside a quoted statement list. Trying to quote a statement in the same way as an expression will cause a parse error.
>`{ def a := 4 } >>def a := 4 >`{ def tab[5] { m() }; tab[3] := n() } >>def tab[5] { m()}; tab[3] := n()
`({ |a, b| a + b})
or as a statement list:
`{ |a, b| a + b}
To quote a literal closure with the latter form, the vertical bars may not be ommited, even if the closure takes no arguments.
`{ || a + b }
yield a literal closure expression, while
`{ a + b}
yields a statement list.
Tables
Literal tables can already be defined as follows:
>def tab := [ 1+2, 3+4, 5+6 ] >>[3, 7, 11]
With this construct, all the elements of the literal table are evaluated. By quoting a literal table, all the elements are quoted instead of evaluated:
>def tab := `[ 1+2, 3+4, 5+6 ] >>[1.+(2), 3.+(4), 5.+(6)]
Unquoting
Inside a quotation, an expression can be unquoted as well. An unquotation escapes from the quotation and causes the unquoted expression to be evaluated. The return value is then used as the quotation of the unquotation.
Unquoting an expression is done with the #
operator.
>def msg() { `foo } >><closure:msg> >def arg(n) { n+5 } >><closure:arg> >`(o.#(msg())(#(arg(1)))) >>o.foo(6)
Splicing
Splicing can already be used without quoting:
>def upTo(n) { def idx := 0; def tab[n] { idx := idx + 1 } } >><closure:upTo> >[ 7, 8, 9, @upTo(4) ] >>[7, 8, 9, 1, 2, 3, 4]
Splicing can also be used in combination with quoting and unquoting. AmbientTalk provides the unquote-splice operator #@
that can be used to splice the value of an unquotation into a quoted expression.
>`(o.m(a, b, #@(upTo(5)))) >>o.m(a, b, 1, 2, 3, 4, 5) >`[ @upTo(3), #@(upTo(2)), #(upTo(3))] >>[@upTo(3), 1, 2, [1, 2, 3]]
First-class abstract grammar
Quoting an AmbientTalk expression results in an the parse tree of that expression. Like any value in AmbientTalk, parse trees are objects that respond to messages. This means that the abstract grammer of AmbientTalk is first-class: programs can manipulate and create asbtract grammar elements.
>`(f(1, 2, 3)).function >>f >`(f(1, 2, 3)).arguments >>[1, 2, 3]
Any abstract grammar element can serve as a prototype for a new one:
>def application := `(f(1, 2, 3)) >>f(1, 2, 3) >application.new(`g, [4, 5, 6]) >>g(4, 5, 6)
Read / Eval / Print
AmbientTalk reifies the read, eval and print operations. This means that you can read any string and get the responding syntax tree for it, evaluate any syntax tree and get a value for it, and print any value and get a string representation of the value.
>read: "1+2" >>1.+(2) >eval: `(1+2) in: self >>3 >print: self >>"<object:8322247>"
Eval is a keyworded message that takes another parameter, namely the object in whose scope the expression must be evaluated.
>def o := object: { def x := 4 } >><object:3281169> >eval: `x in: o >>4