2.3.2.4. Primary expressions¶
Translation of a primary expression P
to an instruction sequence tprimary(P)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This chapter specifies the semantics of Kink programs as transformation into abstract instructions of the abstract stack machine. The transformation is comprised of the two steps desugaring and translation.
Transformation of a program into the desugared form.
The program which is the result of desugaring of another program.
Transformation of the desugared form of the program into a sequence of abstract instructions.
The following is an example program.
:foo <- {
:Vec = [10 20 30]
Vec.each{(:E) bar(E) }
}
The program above is desugared as follows.
\binding:foo.op_store({
{ [\binding:Vec].op_store(\binding._Args)
\binding.Vec.each({
[\binding:E].op_store(\binding._Args)
\binding.bar[()](\binding.E)
})
}.call(() [[10 20 30]])
})
Then translated into abstract instructions as follows.
(binding)
(varref "foo")
(dup)
(load "op_store")
(dup)
(checkfun)
(flip)
(emptyvec)
(binding)
(fun
(enclosingbinding)
(clonebinding)
(dup)
(setbinding)
(storerecvargs)
(binding)
(fun
(enclosingbinding)
(clonebinding)
(dup)
(setbinding)
(storerecvargs)
(emptyvec)
(binding)
(varref "Vec")
(add)
(dup)
(load "op_store")
(dup)
(checkfun)
(flip)
(emptyvec)
(binding)
(load "_Args")
(add)
(call "op_store")
(remove)
(binding)
(load "Vec")
(dup)
(load "each")
(dup)
(checkfun)
(flip)
(emptyvec)
(binding)
(fun
(enclosingbinding)
(clonebinding)
(dup)
(setbinding)
(storerecvargs)
(emptyvec)
(binding)
(varref "E")
(add)
(dup)
(load "op_store")
(dup)
(checkfun)
(flip)
(emptyvec)
(binding)
(load "_Args")
(add)
(call "op_store")
(binding)
(load "bar")
(dup)
(checkfun)
(nada)
(emptyvec)
(binding)
(load "E")
(add)
(call "bar")
)
(add)
(call "each")
)
(dup)
(load "call")
(dup)
(checkfun)
(flip)
(emptyvec)
(nada)
(add)
(emptyvec)
(num 10)
(add)
(num 20)
(add)
(num 30)
(add)
(add)
(call "call")
)
(add)
(call "op_store")
This section defines desugaring in informal style.
A Kink program
is composed of zero or more toplevel expressions.
When a program is composed of expressions E1
, E2
, ,,, En
,
the program is desugared to a parentheses expression (E1 E2 ,,, En)
.
A let clause in the form E1 = E2 S
,
where E1
and E2
are expressions
and S
is a substantial_seq
,
is desugared to {(E1) S }.call(() [E2])
.
Example program with let clauses:
:fun <- {
:add = {(:X :Y) X + Y }
:Sum = add(10 20)
stdout.print_line(Sum.show) # => 30
}
The program above is desugared to the following program.
:fun <- {
{(:add)
{(:Sum)
stdout.print_line(Sum.show)
}.call(() [add(10 20)])
}.call(() [{(:X :Y) X + Y }])
}
Operator expressions are syntactic sugar for
member call expressions (member_call
).
Here is the list of operators.
Priority |
Token type |
Operators |
Associativity |
---|---|---|---|
Lowest |
|
Non-associative |
|
|
Right-associative |
||
|
Right-associative |
||
|
Non-associative |
||
|
Left-associative |
||
|
Left-associative |
||
Highest |
|
Unary |
Each operator expression is desugared as follows.
Operator expression |
Desugared as |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Formal receivers and formal arguments in function bodies (fun_body
)
are syntactic sugar for member call expressions (member_call
).
Function bodies are categorized in four groups:
with or without the formal receiver, and with or without the formal arguments.
The following table describes how each group is desugared.
In the table, C
denotes a sequence (seq
),
E
denotes an expression
,
and VB
denotes a vector body (vec_body
),
Formal receiver |
Formal arguments |
Seq after formal receiver and arguments |
Desugared as |
---|---|---|---|
∅ |
∅ |
|
|
∅ |
|
|
|
|
∅ |
|
|
|
|
|
|
Therefore, fun1
and fun2
in the following example are equivalent.
:fun1 <- {[:Self](:X :Y :Z)
'result'
}
:fun2 <- {
:Self <- _Recv
[:X :Y :Z] <- _Args
'result'
}
Actual arguments vectors (args
) are categorized in two groups:
those with parentheses (paren_args
) and without parentheses.
The following table describes how each group of actual arguments vectors
are desugared.
In the table, E1
, E2
, ... En
denotes zero or more elements producers (elements_producer
).
FB1
, FB2
, ... FBm
denotes function bodies (fun_body
)
of zero or more function arguments (fun_arg
) in the original form.
or zero or more functions (fun
) in the desugared form.
Original form |
Desugared as |
---|---|
|
|
|
|
Therefore, in the following example,
each pair of invocations of show
, if
and fold
are mutually equivalent.
Num.show
Num.show()
if(Str.empty?){ stdout.print_line('empty') }
if(Str.empty? { stdout.print_line('empty') })
Vec.fold(0){(:X :Y) X + Y}
Vec.fold(0 {(:X :Y) X + Y})
Local load expressions (local_load
) are syntactic sugar for
member load expressions (member_load
) of the local binding.
The local load expression in the form Data
is desugared to \binding.Data
.
The local load expression in the form $fun
is desugared to \binding$fun
.
In the following example, fun1
and fun2
are equivalent,
thus the invocations of both functions output 42
to the standard output.
:fun1 <- {(:Val :output)
:output_copy = $output
output_copy(Val)
}
fun1(42 {(:X) stdout.print_line(X.show) }) # => 42
:fun2 <- {(:Val :output)
:output_copy = \binding$output
output_copy(\binding.Val)
}
fun2(42 {(:X) stdout.print_line(\binding.X.show) }) # => 42
Local reference expressions (local_varref
) are syntactic sugar for
member reference expressions (member_varref
) of the local binding.
The local reference expression in the form :Data
is desugared to \binding:Data
.
The local reference expression in the form :fun
is desugared to \binding:fun
.
In the following example, fun1
and fun2
are equivalent,
thus the invocations of both functions output 42
to the standard output.
:fun1 <- {
:Val = 42
:output = {(:X) stdout.print_line(X.show) }
output(Val)
}
fun1 # => 42
\binding:fun2 <- {
\binding:Val = 42
\binding:output = {(\binding:X) stdout.print_line(X.show) }
output(Val)
}
fun2 # => 42
Local call expressions (local_call
) are syntactic sugar for
member call expressions (member_call
) of functions owned by the local binding.
The local call expression in the form fun(VB)
is desugared to \binding.fun[()](VB)
, where VB
is a vector body.
The local call expression in the form fun[R](VB)
is desugared to \binding.fun[R](VB)
,
where R
is an expression and VB
is a vector body.
In the following example, fun1
and fun2
are equivalent,
thus the invocations of both functions output hello world
to the standard output.
:print_arg <- {(:Arg)
stdout.print_line(Arg.show)
}
:print_recv <- {[:R]
stdout.print_line(R.show)
}
:fun1 <- {
print_arg('hello ')
print_recv['world']
}
fun1 # => hello world
:fun2 <- {
\binding.print_arg[()]('hello ')
\binding.print_recv['world']()
}
fun2 # => hello world
This section defines translation as transformation from the desugared form of the program into abstract instruction <abstract instruction>.
In the desugared form,
a program
is composed of a single parentheses expression.
Translation of a program P
to a sequence of abstract instructions tprogram(P)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
In the desguared form, thus without let clauses,
a sequence (seq
) is a sequence of zero ore more expressions.
If the sequence consists of no expressions, it produces the value ()
(called “nada”).
If the sequence consists of one or more expressions,
it evaluates the expressions in the order they appears,
and produces the result of the last expression.
Grammatically, a sequence is composed of either empty
or a substantial sequence (substantial_seq
).
A substantial sequence is composed of a single expression,
or a pair of an expression and a substantial sequence.
Translation of a sequence S
to an instruction sequence tseq(S)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
Translation of a substantial sequence
SS
to an instruction sequence tsubstantial_seq(SS)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
E : expression SSS : substantial_seq |
|
In the following example,
fun1
outputs the result of an empty sequence, which is nada.
fun2
outputs the result of
a sequence comprising three expressions 'foo'
, 'bar'
and 'baz'
;
the result is 'baz'
.
:fun1 <- {
:Result = ()
stdout.print_line(Result.repr) # => nada
}
fun1
:fun2 <- {
:Result = ('foo' 'bar' 'baz')
stdout.print_line(Result.repr) # => "baz"
}
fun2
In the normalized form,
an expression
can be eventually reduced to a single primary expression (primary
).
Therefore, translation of an expression E
to an instruction sequence
texpression(E)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
Translation of a primary expression P
to an instruction sequence tprimary(P)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A number expression (num
) produces a number value.
Translation of a number expression N
to an instruction tnum(N)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
In the following example,
fun1
outputs the result of the integer number expression 42
.
fun2
outputs the result of the decimal number expression 3.14
.
:fun1 <- {
:Result = 42
stdout.print_line(Result.show) # => 42
}
fun1
:fun2 <- {
:Result = 3.14
stdout.print_line(Result.show) # => 3.14
}
fun2
A string expression (str
) produces a string value.
Translation of a string expression S
to an instruction tstr(S)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
The following example outputs the result of the string expression 'foo'
.
:Result <- 'foo'
stdout.print_line(Result) # => foo
A binding expression produces the current binding.
Translation of a binding expression CE
to an instruction tbinding(CE)
is defined as follows.
Composition of |
|
---|---|
|
|
The following example outputs the value of the variable Val
of the current binding,
namely, the local variable Val
.
:Val <- 42
stdout.print_line(\binding.Val.show) # => 42
A pair of parentheses is used to enclose a sequence as a primary expression.
Translation of a parentheses expression P
to an instruction sequence tparen(P)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
In the following example,
the addition 2 + 4
is calculated before the mulliplication.
:Val <- 7 * (2 + 4)
stdout.print_line(Val.show) # => 42
A vector expression is used to make a vector.
Translation of a vector expression V
to an instruction sequence tvec(V)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
A vector body (vec_body
) is used in vector expressions and actual arguments in function calls
(and formal arguments in not normalized forms) to produce elements of vectors.
Translation of a vector body VB
to an instruction sequence tvec_body(VB)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
EP : elements_producer VVB : vec_body |
|
In the following example,
the vector Spreaded
is expanded in the second vector literal.
:Spreaded <- [42 3.14]
:Vec <- ['foo' ...Spreaded 'bar']
stdout.print_line(Vec.repr) # => ["foo" 42 3.14 "bar"]
In the following example,
the vector Spreaded
is spreaded in the arguments vector for the function call of fun
.
:fun <- {
stdout.print_line(_Args.repr)
}
:Spreaded <- [42 3.14]
fun('foo' ...Spreaded 'bar') # => ["foo" 42 3.14 "bar"]
An elements producer (elements_producer
) is a content of vector bodies.
Translation of an element producer EP
to an instruction sequence telements_producer(EP)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
A function expression (fun
) produces a function value.
Translation of a function expression F
to an instruction sequence tfun(F)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|
|
A member load expression (member_load
) loads a variable of the owner.
Translation of a member load expression D
to an instruction sequence tmember_load(D)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
P : primary N : DATA_SYM |
|
|
P : primary V : FUN_SYM |
|
A member reference expression (member_varref
) produces a variable reference of the owner.
Translation of a member reference expression R
to an instruction sequence tmember_varref(R)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
P : primary N : DATA_SYM |
|
|
P : primary V : FUN_SYM |
|
A member call expression (member_call
) invokes a function.
Translation of a member call expression C
to an instruction sequence tmember_call(C)
is defined as follows.
Composition of |
Where |
|
---|---|---|
|
|
|
|
|