6.3. kink/BINDING¶
6.3.1. type binding¶
A `binding` value, or simply a binding, is an owner of local variables.
You can get the binding of the current function call by `\binding` in the program.
:foo <- {
:Num = 42
stdout.print_line(\binding.Num.repr)
}
foo # => 42
You can make a binding, and evaluate a program using it.
:BINDING.require_from('kink/')
:PROGRAM.require_from('kink/program/')
:Binding <- BINDING.new
Binding:Num <- 42
:Program <- PROGRAM.new('program' 'Num * 2')
:eval_program <- Program.compile{(:C)
C.binding(Binding)
}
stdout.print_line(eval_program.repr) # => 84
Every binding has functions listed below, like `new_val` or `stdout`, as local variables. Those functions are called “preloaded functions”.
6.3.1.1. nada¶
“Just this creaking metal sign that said nada, nada, against the blue sky. I used to wake up hollering” ―― The Crying of Lot 49 (1966, Thomas Pynchon).
`nada` is a constant of a meaningless value. `nada` value is used when there is no other meaningful value to use. For example, `<-` operator of variable referenecs does not have any meaningful value to return, so it returns `nada`.
stdout.print_line((:X <- 49).repr) # => nada
6.3.1.2. true¶
`true` is a constant of the true value of type `bool`.
6.3.1.3. false¶
`false` is a constant of the false value of type `bool`.
6.3.1.4. new_val(...[Sym0 Val0 Sym1 Val1 ,,,])¶
`new_val` returns a new value. If arguments are passed, `new_val` also assigns values to variables of the created value.
Variable assignment
Let `O` be the created value, `N` be a non-negative integer, and Sym(0), Val(0), Sym(1), Val(1) ,,, Sym(N - 1), Val(N - 1) are the passed args.
For each integer `i` from 0 to `N - 1`, in ascending order, `new_val` performs variable-store operation for the variable (owner=O, symbol=Sym(i)), and Val(i) as the content.
Preconditions
The number of args must be even.
`Sym0`, `Sym1` ,,, must be `str` values.
Example
:V <- new_val(
'bark' { 'Bow' }
'howl' { 'Wow' }
)
stdout.print_line(V.bark) # => Bow
stdout.print_line(V.howl) # => Wow
The program above is equivalent to the following.
:V <- new_val
V:bark <- { 'Bow' }
V:howl <- { 'Wow' }
stdout.print_line(V.bark) # => Bow
stdout.print_line(V.howl) # => Wow
6.3.1.5. raise(Msg)¶
`raise` raises an exception with `Msg` as the exception message, and the current traces as the traces of the exception.
Precondition
`Msg` must be a `str`.
6.3.1.6. ! Bool / op_lognot(Bool)¶
`!` operator, or `op_lognot` function, returns logical negation of `Bool`.
If `Bool` is true, `op_lognot` returns false.
If `Bool` is false, `op_lognot` returns true.
Precondition
`Bool` must be a `bool`.
6.3.1.7. Bool1 || Bool2 / op_logor(Bool1 $thunk={ Bool2 })¶
`||` operator, or `op_logor` function, performs logical OR operation by short-circuit evaluation.
If `Bool1` is true, `op_logor` returns true.
If `Bool1` is false, `op_logor` tail-calls $thunk.
Precondition
`Bool1` must be a `bool`.
6.3.1.8. Bool1 && Bool2 / op_logand(Bool1 $thunk={ Bool2 })¶
`&&` operator, or `op_logand` function, performs logical AND operation by short-circuit evaluation.
If `Bool1` is true, `op_logand` tail-calls $thunk.
If `Bool1` is false, `op_logand` returns false.
Precondition
`Bool1` must be a `bool`.
6.3.1.9. if(Bool $true_cont ...[$false_cont={}])¶
`if` does 1-way or 2-way branch.
If `Bool` is true, `if` tail-calls $true_cont.
If `Bool` is false, `if` tail-calls $false_cont.
Preconditions
`Bool` must be a `bool`.
$true_cont must be a thunk.
$false_cont must be a thunk.
Example: 1 way branch
:print_if_even <- {(:N)
if(N % 2 == 0){
stdout.print_line('even number {}'.format(N.repr))
}
}
print_if_even(8) # => even number 8
print_if_even(11) # => (no output)
Example: 2 way branch
:compare <- {(:Num)
if(Num < 100
{ 'less than 100' }
{ 'greater than or equal to 100' }
)
}
stdout.print_line(compare(50)) # => less than 100
stdout.print_line(compare(200)) # => greater than or equal to 100
6.3.1.10. branch(...[$cond0 $then0 $cond1 $then1 ,,,])¶
`branch` performs a multiway branch.
First, `branch` calls $cond0, $cond1 ,,, with no args, in ascending order, until one of them returns true. If none of them returns true, `branch` raises an exception.
Second, `branch` tail-calls the `then` thunk corresponding to the `cond` thunk which returned true, with no args.
Preconditions
The number of args must be even.
$cond0, $cond1, ,,, must be thunks which return `bool`.
$then0, $then1, ,,, must be thunks.
Example
:Sorted_nums <- [1 2 3 5 8 11 19 30 49 89]
# returns whether Sorted_nums contains N, by binary search algorithm
:contain? <- {(:N)
:in_range? <- {(:From :To)
From < To && (
:Ind = (From + To) // 2
:T = Sorted_nums.get(Ind)
branch(
{ T < N } { in_range?(Ind + 1 To) }
{ T > N } { in_range?(From Ind) }
{ true } { true }
)
)
}
in_range?(0 Sorted_nums.size)
}
stdout.print_line(contain?(30).repr) # => true
stdout.print_line(contain?(42).repr) # => false
6.3.1.11. stdin¶
`stdin` is a constant of the scanner+input of the standard input of the runtime.
`stdin` as a `scanner` decodes byte streams using CHARSET.default.
Example: read all from stdin then write it to stdout
:Bin <- stdin.read_all
stdout.write(Bin)
Example: cat -n with the default charset
:loop <- {(:N)
stdin.scan_line{(:C)
C.on_success{(:Line)
stdout.print("{}\t{}".format(N Line))
loop(N + 1)
}
C.on_eof{}
}
}
loop(1)
Example: cat -n with UTF-8 input/output
:INPUT_SCANNER.require_from('kink/io/')
:OUTPUT_PRINTER.require_from('kink/io/')
:CHARSET.require_from('kink/')
:Scanner <- INPUT_SCANNER.new(stdin CHARSET.utf8)
:Printer <- OUTPUT_PRINTER.new(stdout CHARSET.utf8 "\n")
:loop <- {(:N)
Scanner.scan_line{(:C)
C.on_success{(:Line)
Printer.print("{}\t{}".format(N Line))
loop(N + 1)
}
C.on_eof{}
}
}
loop(1)
6.3.1.12. stdout¶
`stdout` is a constant of the printer+output for the standard output of the runtime.
`stdout` as a `printer` uses STR.default_newline as the newline `str`, and encodes strings using CHARSET.default.
6.3.1.13. stderr¶
`stderr` is a constant of the printer+output of the standard error output of the runtime.
`stderr` as a `printer` uses STR.default_newline as the newline `str`, and encodes strings using CHARSET.default.
`write`, `print`, `print_line`, `flush`, and `close` methods of `stderr` are synchronized, in order that multiple threads can output error messages to `stderr`.
If an encoding error happens on print_xxx methods, `stderr` writes a replacement byte sequence, rather than resulting in an IO error. The reason is that the string written to `stderr` is more useful even incomplete, rather than an error message of the conversion error.
6.3.2. BINDING.new¶
`new` makes a new `binding`.
6.3.3. BINDING.is?(Val)¶
`is?` returns whether `Val` is a `binding` value.