# -*- pliant -*-

# @@PLEAC@@_NAME
# @@SKIP@@ Pliant

# @@PLEAC@@_WEB
# @@SKIP@@ http://www.fullpliant.org/

# @@PLEAC@@_INTRO
# @@SKIP@@ Written for version 73.
# @@SKIP@@ Code is function code to allow local variables (for readibility).

# @@PLEAC@@_APPENDIX

# multiline strings may be achieved by addition of a new
# parser filter
# We give here a full answer which goes a bit out the scope
# of a basic tutorial, but emphasizes the power of Pliant reflexiveness.
#

module "/pliant/language/parser.pli"
module "/pliant/language/compiler.pli"

#
# parser filter declaration helper function
#     mod is the module in which the filter is declared
#     section_name is the section in which the filter is inserted
#     ad is the address of the filter function
#     adp is the address of the filter parameter
#
function declare_filter2 mod section_name ad adp
  arg_rw Module mod; arg Str section_name; arg Address ad; arg Arrow adp
  var Link:ParserFilter lp :> new ParserFilter
  lp function :> ad map Function
  lp parameter := adp
  mod define section_name addressof:lp

#
# declare_filter meta
#
#    syntax: declare_filter section filter parameter [link|copy]
# inserts the filter 'filter' in section 'section' of the caller's module
# with parameter 'parameter'; By default, parameter is copied.
# parameter may be mapped by using 'link' keyword
#

meta declare_filter e
  if (e:size <> 2) and (e:size<>3) and (e:size<>4)
     return
  var Bool copy:=true
  if e:size=4
     if not e:3:is_pure_ident
        return
     if e:3:ident="copy"
        copy:=true
     eif e:3:ident="link"
        copy:=false
     else
        return
  var Link:Expression ef :> expression immediat (the_function fun ParserContext Str Address) substitute fun e:1 near e
  var Address ad := ef evaluate
  if error_notified
    return
  if ad=null
    error error_id_unexpected "Failed to evaluate expression at "+e:position
    e set_void_result
  var Arrow adp
  if e:size>=3
   e:2 compile ?
   var Pointer:Type ptype :> e:2:result:type
   var Link:Expression type_id :> expression ident ptype:name near e:2
   if copy
      ef :> expression immediat (new ptype pvalue) substitute ptype type_id substitute pvalue e:2 near e
      adp := ef evaluate
   else
      adp := e:2 evaluate
   if error_notified
      return
   if adp=null
      error error_id_unexpected "Failed to evaluate expression at "+e:position
      e set_void_result
  if (addressof e:module:external)=null
     var Link:Argument adr :> argument constant Address addressof:(e:module)
  else
     var Link:Argument adr :> argument constant Address addressof:(e:module:external)
  var Link:Argument ma :> argument indirect Module adr 0
  e add (instruction (the_function declare_filter2 Module Str Address Arrow) ma (argument constant Str e:0:ident) (argument constant Address ad) (argument constant Arrow adp))
  e set_void_result
#
# generic parse_text parser filter
# parameter is assumed to be a string corresponding to the keyword used.
# If parameter is "foo", then
#   foo a b c
#     hello
#    How are you ?
#       this morning...
#
# will be parsed as if written
#
#   foo a b c
#    " hello"
#    "How are you ?"
#    "   this morning..."
#

function parse_text context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  var Pointer:Str kwd :> parameter map Str
  if (line 0 kwd:len)=kwd
    var Int x := 0
    var Pointer:Str l :> context:current_line map Str
    while l:x = " "
       x+=1
    var Pointer:Arrow cur :> context:text next context:current_line
    while cur<>null and { var Pointer:Str l :> cur map Str ; (l 0 x+1)=(repeat x+1 " ") or l=(repeat l:len " ") }
      var Str t := l x+1 l:len
      l := (repeat x+1 " ")+string:t
      cur :> context:text next cur

#
# simple multi-line text meta
#
# syntax:
# inline_text [leftcut|ignorefirst]
#   some text
#    over multiple lines...
#
meta inline_text e
  if e:size<1
     return
  var Link:Expression body :> e e:size-1
  if body:ident<>"{}" or body:size=0
     return
  for (var Int i) 0 body:size-1
     var Address ad := body:i constant Str
     if ad=null
        error error_id_unexpected "text: argument #"+string:i+" is not a constant Str"
        return
  var Bool leftcut := false; var Int leftmargin:=0; var Int start:=0
  var Str s
  if e:size>1 and e:0:is_pure_ident
   if e:0:ident="leftcut"
     leftcut:=true
     leftmargin := -1 # stands for infinity
   eif e:0:ident="ignorefirst"
     start := 1
     var Pointer:Str ss :> (body:0 constant Str) map Str
     ss eparse spaces:s
     leftmargin := s:len
  if leftcut
    for (var Int i) 0 body:size-1
       var Pointer:Str ss :> (body:i constant Str) map Str
       ss eparse spaces:s
       if s:len<leftmargin or leftmargin<0
         leftmargin:=s:len
  s:=""
  for (var Int i) start body:size-1
    var Pointer:Str ss :> (body:i constant Str) map Str
    s += (ss leftmargin ss:len)+"[lf]"
  e set_result (argument constant Str s) access_read

#
# filter declaration for immediat use
#
declare_filter 'pliant parser basic types' parse_text "inline_text" copy


# @@PLEAC@@_1.0
# In Pliant, the standard type to handle character strings is Str.
# String variables must be declared -- if no value is given it's
# value is the empty string ("") if the variable is global.
var Str string

# special characters
string := "[lb]"                   # character '['
string := "[rb]"                   # character ']'
string := "[lf]"                   # line feed
string := "[cr]"                   # carriage return
string := "[tab]"                  # tabulation
string := "[0]"                    # null character
string := "Jon said [dq]hello[dq]" # literal double quotes

#
# multiline text using inline_text meta and parse_text filters defined 
# in the Appendix
#

var Str string := inline_text
 This is a multiline here document
 terminated by indentation rule
 (the first indenting space is ignored).
 In the multiline, "special" characters have not to be
 [quoted].

# remark each lines of string is ended with a [lf]

var Str string := inline_text leftcut
     This is a multiline here document
       terminated by indentation rule
   with left margin given by the leftest string

var Str string := inline_text ignorefirst
       ! left margin is here
           This is a multiline here document
  gna  with all characters left to the margin ignored,
       as long as properly indented.


# @@PLEAC@@_1.1
var Str s:="some string"

# extraction of at most length characters (less if the required
# length is not available in the string) -> new string

var Str s1 
s1 := s offset length
s1 := s offset s:len      # extracts the end of the string

# same, but the string is really a substring (like in Perl)
# to do this, we add new methods to Str:

method p map s from to
  arg_rw Str p; arg Str s; arg Int from length
  check to < s:len
  p set (s:characters translate Char from) to-from false
#

s1 map s offset offset+length
s1 map s offset s:len-1

#
# The equivalent of unpack in Pliant is eparse. However,
# no parsing method is present by default for fixed length
# strings.
# We should create some function FixedStr to create the
# type "string of length xxx" and the from_string method
# on these types. Then, the unpack could be writen as

var FixedStr:5 leading
var FixedStr:3 dummy
var FixedStr:8 s1 s2
var Str trailing data
data eparse leading dummy s1 s2 any:trailing

#
# A string may be accessed as an array of Char, but if we
# way to transfer a Str into an Array of Char, we need a loop
#
var Array:Char chars
for (var Int i) 0 s:len
  chars i := s i

#
#

s := "This is what you have"

# strings do not support backwards indexing as perl does, but we may
# add this functionality
method s 'new substring' i j -> ss
  arg Str s ss; arg Int i j
  strong_definition
  ss:= s (shunt i<0 s:len+i i) j
alias '' '. new substring' 
#
first  := string 0 1              # "T"
start  := string 5 2              # "is"
rest   := string 13 string:len    # "you have"
last   := string -1 string:len    # "e"
end    := string -4 string:len    # "have"
piece  := string -8 3             # "you"
#--------------------
string := "This is what you have"
console string
#This is what you have


# @@PLEAC@@_1.4
# characters have type Char in Pliant
var Char char:="X"
var Int num := char number        # gets the ASCII code of char
char := character num             # ASCII to character
#-----------------------------
# Here, we use a string
var Str string:="Hello"
num := string:0:number            # ASCII code of first character
string := character num           # implicit Char->Str cast
#-----------------------------
var Int ascii_value := "e":number # now 101
var Char char := character 101    # now "e"
#-----------------------------
var Str hal := "HAL"
var Str ibm := hal
for (var Int i) 0 ibm:len-1
  ibm:i := character hal:i:number+1


# @@PLEAC@@_1.5
# Since Pliant++ strings can be accessed one character at a time,
# there's no need to do any processing on the string to convert
# it into an array of characters

var Str s

for (var Int i) 0 s:len-1
  # do something with s:i
#------------------------------------------
# we use an Index to sort implicitely the keys
module "/pliant/language/unsafe.pli"         # at the moment Index is still considered unsafe
module "/pliant/language/type/set/each.pli"  # each.pli has to be linked to explicitely
var (Index Char Bool) seen
var Str string := "an apple a day"
for (var Int i) 0 string:len-1
  if not (seen exists string:i)
    seen insert string:i true
console "unique chars are: "
each c seen                       # warning, c is the value associated with the key
  console (seen key c)
console eol
# unique chars are:  adelnpy
#-------------------------------------------
var Int sum:=0
for (var Int i) 0 string:len-1
  sum += s:i:number
console sum eol
# prints "1248" if string was "an apple a day"
#---------------------------------------------


# @@PLEAC@@_1.13
var Str str := "This is a [dq]string[dq] with [lf] special [lb]characters[rb] in it"
var Str quoted := string str
# "This is a [lb]dq[rb]string[lb]dq[rb] with [lb]lf[rb] special [lb]lb[rb]characters[lb]rb[rb] in it"
#
# back to unquoted string (quoted -> str)
quoted eparse str
#---------------------------------------------


# @@PLEAC@@_1.15
#
# quoted " ([lb][dq][rb]) are implictely dequoted when arising in a parsed string
# 
var Str string := "XYZZY,[dq][dq],[dq]O'Reilly, Inc[dq],[dq]Wall, Larry[dq],[dq]a [lb]dq[rb]glug[lb]dq[rb] bit[dq], another [dq]glub[dq] bit, 5, [dq]Error, Core Dumped[dq]"
var Str a
var Str b:=string+","
var Array:Str fields
while b<>""
  if not (b parse a "," any:b)  # if not a quoted string
    b parse any:a "," any:b     # it is not quoted and ends with the next ","
  fields += a
for (var Int i) 0 fields:size-1
  console "#" i ":" fields:i eol

#0 : XYZZY
#1 :
#2 : O'Reilly, Inc
#3 : Wall, Larry
#4 : a "glug" bit
#5 : another "glub" bit
#6 : 5
#7 : Error, Core Dumped 
#-----------------------------

# ^^PLEAC^^_2.1
#-----------------------------

if (string eparse (var Int i))
  # is an integer -> i
else
  # is not
#-----------------------------
if (string eparse (var Float f))
  # is a float -> f
else
  # is not
#-----------------------------
function is_numeric s -> ok
  arg Str s; arg Bool ok
  ok := s eparse (var Int i)
#-----------------------------

# ^^PLEAC^^_2.3
#-----------------------------
var Float unrounded := 0.255
var Float rounded := (cast unrounded*100 Int)/100
console "Unrounded: " unrounded eol "Rounded: " rounded eol

Unrounded: 0.255
Rounded: 0.26
#-----------------------------

# ^^PLEAC^^_2.4
#-----------------------------

function dec2bin i -> s
  arg Int i; arg Str s
  s := string i "radix 2"
var Str binstr := dec2bin 54      # binstr is "110110"
#-----------------------------

# ^^PLEAC^^_2.5
#-----------------------------
for (var Int i) X Y
     # i is set to every integer from X to Y, inclusive

for (var Int i) X Y step 7
     # i is set to every integer from X to Y, stepsize = 7
#-----------------------------
print "Childhood is: ";
for (var Int i) 5 12
  console i " "
console eol

Childhood is: 5 6 7 8 9 10 11 12
#-----------------------------

# ^^PLEAC^^_2.11
#-----------------------------
module "/pliant/math/functions.pli"

function deg2rad d -> r
  arg Float d r
  return d/180*pi

function rad2deg r -> d
  arg Float r d
  return r/pi*180
#-----------------------------
radians := deg2rad degrees
degrees := rad2deg radians
#-----------------------------
function degree_sine d -> s
  arg Float d s
  s := sin deg2rad:d
#-----------------------------

# ^^PLEAC^^_2.12
#-----------------------------
f := tan 3.7
f := acos 3.7 # returns undefined
f := acos 0.2
f := tan (pi/2) # actualy returns 1.63317787284e16
#-----------------------------

# ^^PLEAC^^_2.13
#-----------------------------
log_e := log value
#-----------------------------
function log_base base value -> l
  arg Float base value l
  return log:value/log:base
#-----------------------------
# log_base defined as above
answer := log_base 10 10000
#-----------------------------

# ^^PLEAC^^_2.15
#-----------------------------
module "/pliant/language/compiler.pli"
module "/pliant/language/parser.pli"

type Complex
  field Float real imaginary        # define type

function 'cast Complex' f -> z      # extension cast Float -> Complex
  arg Float f; arg Complex z
  extension
  z real := f
  z imaginary := 0

function 'cast Float' z -> f        # reduction cast Complex -> Float
  arg Float f; arg Complex z
  reduction
  if z:imaginary<>0
    error error_id_arithmetic "The value is not a real number"
  else
    f := z real

#
# Define a parser for notation like 3i. i will not be valid, 1i will be.
#
function parse_imaginary context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if not (line parse (var Float data) word:"i" offset:(var Int offset))
    return
  var Link:Complex z :> new Complex
  z real := 0
  z imaginary := data
  context add_token addressof:z
  context forward offset

gvar ParserFilter img_filter
img_filter function :> the_function parse_imaginary ParserContext Str Address
constant 'pliant parser basic types' img_filter
export 'pliant parser basic types'

# basic functions on complex numbers

function '+' z1 z2 -> z
  arg Complex z1 z2 z
  z real := z1:real+z2:real
  z imaginary := z1:imaginary+z2:imaginary

function '-' z1 z2 -> z
  arg Complex z1 z2 z
  z real := z1:real-z2:real
  z imaginary := z1:imaginary-z2:imaginary

function '*' z1 z2 -> z
  arg Complex z1 z2 z
  z real := z1:real*z2:real-z1:imaginary*z2:imaginary
  z imaginary := z1:real*z2:imaginary+z2:real*z1:imaginary

# how to write it

method z 'to string' options -> s
  arg Complex z ; arg Str options ; arg Str s
  if z:imaginary=0
    return (string z:real)
  eif z:real=0
    return (string z:imaginary)+"i"
  return (string z:real)+"+"+(string z:imaginary)+"i"
#-------------------------
var Complex c := a * b
#-------------------------
var Complex a := 3+5i
var Complex b := 2-2i
c := a*b
console "c = " c eol

c = 16+4i
#-------------------------
var Link:Complex za :> new Complex 3+5i
var Link:Complex zb :> new Complex 2-2i
var Link:Complex zc :> new Complex

zc := za * zb
console "c = " zc eol

c = 16+4i
#-------------------------

# @@PLEAC@@_10.0
gvar Int greeted               # global variable (but maybe local to module)
function hello
  greeted += 1
  console "hi there" eol
#---------------------------
hello
#---------------------------


# @@PLEAC@@_5.0
module "/pliant/language/unsafe.pli"
var (Dictionary Str Int) age
# insertion
implicit age
  insert "Nat" 24
  insert "Jules" 25
  insert "Josh" 17
# when you know keys already exist:
age "Nat" := 24
age "Jules" := 25
age "Josh" := 17
#-----------------------------
var (Dictionary Str Str) food_color
implicit food_color
  insert "Apple" "red"
  insert "Banana" "yellow"
  insert "Lemon" "yellow"
  insert "Carrot" "orange"
#-----------------------------


# @@PLEAC@@_5.1
#-----------------------------
 dict insert key value
#-----------------------------
# food_color defined per the introduction
food_color insert "Raspberry" "pink"
console "Known foods:" eol
each x food_color
  console (food_color key x) eol

 Known foods:
 Banana
 Apple
 Raspberry
 Carrot
#-----------------------------


# @@PLEAC@@_5.2
#-----------------------------
# does dict have a value for key ?
if (dict exists key)
  # it exists
else
  # it doesn't
 
#-----------------------------
# food_color per the introduction

var List:Str fruits; fruits += "Banana"; fruits += "Martini"
each name fruits
  if (food_color exists name)
    console name " is a food." eol
  else
    console name " is a drink." eol

 Banana is a food.
 Martini is a drink.
#-----------------------------
age := new (Dictionary Str Int)
implicit age
  insert "Toddler" 3
  insert "Unborn" 0
  insert "Phantasm" undefined

var List:Str things
things+="Toddler", things+="Phantasm"; things+="Relic"

each thing things
  console thing ": "
  if (age exists thing)
    console "Exists "
    console (shunt age:thing<>undefined "Defined " "")
    console (shunt age:thing>0 "True " "")
  console eol

# Toddler: Exists Defined True 
# Unborn: Exists Defined 
# Phantasm: Exists 
# Relic: 
#-----------------------------


# @@PLEAC@@_5.3
#-----------------------------
# remove the first element in dict with key value
dict -= dict value

#-----------------------------
# food_color as per Introduction
function print_foods
  each food food_color
    console "key : " (food_color key food)  ", value: " (shunt food="" "(undef)" food) eol
  console eol

console "Initially:" eol
print_foods

console "With Banana undef" eol
food_color "Banana" := "" # no true way to undef a Str...
print_foods

console "With Banana deleted" eol
food_color -= food_color "Banana"
print_foods

# Initially:
# key : Lemon, value: yellow
# key : Banana, value: yellow
# key : Apple, value: red
# key : Carrot, value: orange
# 
# With Banana undef
# key : Lemon, value: yellow
# key : Banana, value: (undef)
# key : Apple, value: red
# key : Carrot, value: orange
# 
# With Banana deleted
# key : Lemon, value: yellow
# key : Apple, value: red
# key : Carrot, value: orange
#---------------------------

#-----------------------------
each value dict
  # the key is (dict key value)

#-----------------------------
# food_color per the introduction
each color food_color
  console (food_color key color) " is " color eol

# Banana is yellow.
# Apple is red.
# Carrot is orange.
# Lemon is yellow.

#-----------------------------
var Pointer:Str color :> food_color first
while exists:color
  console (food_color key color) " is " color
  color :> food_color next color
#---------------------------


# @@PLEAC@@_10.1
function hypothenuse a b -> c
  arg Float a b c
  c := (a^2+b^2)^0.5

var Float diag := hypothenuse 3 4  # diag is 5
#----------------------------
console (hypthenuse 3 4) eol       # prints 5
#----------------------------
var Array:Float nums
nums 0 := 1.4; nums 1 := 3.5; nums 2 := 6.7
function int_all t1 -> t2
  arg Array:Float t1; arg Array:Int t2
  t2 := new Array:Int
  for (var Int n) 0 t1:size-1
     t2 i := cast t1:i Int
var Array:Int ints := int_all nums

function int_all2 t1 -> t2         # with object creation
   arg Array:Float t1; arg (Link Array:Int) t2
   t2 :> new Array:Int
   t2 size := t1 size
   for (var Int n) 0 t1:size-1
     t2 i := cast t1:i Int
var (Link Array:Int) ints2 :> int_all2 nums

#-----------------------------

method t trunc_em                  # method implementation
  arg_rw Array:Float t
  for (var Int n) 0 t:size-1
     t i := cast t:i Int

function trunc_em t                # function implementation
  arg_rw Array:Float t
  for (var Int n) 0 t:size-1
     t i := cast t:i Int

nums trunc_em                       # calls the method
trunc_em nums                       # calls the function
#-------------------------------


# @@PLEAC@@_10.2
func somefunc
  var Int variable                  # local variable
  var Str a b c                     # many variables, if same type

  # ...
#---------------------------------


# @@PLEAC@@_10.4
# this meta returns the current Function object
module "/pliant/language/compiler.pli"
meta me e
  if e:size<>0
    return
  var Pointer:Function f :>
    (pliant_general_dictionary first "pliant function") map Function
  if exists:f
    console "compilation for function " f:name eol
    e set_result (argument mapped_constant Function f) access_read+access_constant+access_mapped

# sample use:

function my_function
  console "My name is " me:name eol
#-----------------------------------


# @@PLEAC@@_10.16
function outer i -> j
  arg Int i j
  var Int x := i+35
  function inner i -> j # no clash is possible
    arg Int i j
    var Int x := i*19
    return x
  j := x+inner:x
#-----------------------------------

# ^^PLEAC^^_11.0
#-----------------------------
module "/pliant/lnaguage/unsafe.pli" # using pointers is unsafe
var Pointer:Int sref  # declaration of a reference to an Int
sref :> value         # reference assignment (sref "points" to value content)
#-----------------------------
var Link:Int sref2    # declaration of a link (concerns object, increments reference count)
sref2 :> new Int      # typical use of "new" to create a new object
#-----------------------------
console sref # prints the scalar value that the reference sref refers to
sref := 3    # assigns to sref's referent
#-----------------------------
var Pointer:(Array:Int) aref :> array
#-----------------------------
sref :> null map Int
sref := 4            # runtime error
#-----------------------------
var Link:(Array Int) aref :> new Array:Int    # new array
aref += 3; aref += 4; aref += 5
gvar Link:(Dictionary Str Str) href :> new (Dictionary Str Str) # new hash
implicit href
  insert "How" "Now"
  insert "Brown" "Cow"
#-----------------------------
aref :> null map Array:Int
aref :> new Array:Int
console (cast addressof:aref Int)
1076501816
#-----------------------------

# ^^PLEAC^^_11.1
#-----------------------------
aref :> array
anon_array :> new Array:Int; annon_array += 1; annon_array += 3;
annon_array += 5; annon_array += 7; annon_array += 9;
#-----------------------------
annon_array += 11
#-----------------------------
one := annon_array 0
#-----------------------------
num_items := aref size
#-----------------------------
# check whether an Arrow is the address of an array of Int
if entry_type:arrow <> Array:Int
  error error_id_unexpected "Expected an array reference, not "+entry_type:arrow:name
  return

array_ref += item # append new element to orig array
#-----------------------------
function array_ref -> ref
  arg Link:(Array:Int) ref
  gvar Array:Int array
  ref :> array

var Link:(Array:Int) aref1 :> array_ref
var Link:(Array:Int) aref2 :> array_ref
#-----------------------------
console array_ref:n            # access item in position n
#-----------------------------
each item array_ref
  # item has data

for (var Int idx) 0 array_ref:size-1
  # array_ref:idx has data
#-----------------------------

# ^^PLEAC^^_11.3
#-----------------------------
var Link:(Dictionary Str Str) href :> hash
var Link:(Dictionary Str Str) anon_hash
implicit anon_hash
  insert "key1" "value1"
  insert "key2" "value2"
#-----------------------------
value := href key
#-----------------------------
if entry_type:arrow <> (Dictionary Str Str)
  error error_id_unexpected "Expected a has reference, not "+entry_type:arrow:name
#-----------------------------
each item href
  console (href key item) " => " item eol
#-----------------------------

# ^^PLEAC^^_11.4
#-----------------------------
module "/pliant/language/compiler.pli" # access to Function type
function thefunc s -> i
  arg Str s; arg Int i
  #...
var Link:Function fun :> the_function thefunc Str -> Int

function wrapper s f -> i               # used to perform an indirect call
  arg Str s; arg Function f; arg Int i
  indirect

value := wrapper "hello" fun            # actually calls the_func 
#-----------------------------
var (Dictionary Str (Link Function)) commands   # Function may not be copied, use links.
var Link:Function fun
implicit commands
  fun :> thefunction joy -> Str; insert "happy" fun
  fun :> thefunction sullen -> Str; insert "sad" fun
  fun :> thefunction angry -> Str; insert "mad" fun

module "/pliant/language/ui/ansi_terminal.pli" # access to terminal functions
var Str string := keyboard_input "How are you? "

function wrapper2 fun -> s  # wrapper function for indirect call
  arg Function fun; arg Str s
  indirect
  
if (commands exists string)
  console (wrapper2 commands:string) eol
else
  console "No such command : " string eol
#-----------------------------
type Counter
  field Int start <- 0

function 'cast Int' c -> i   # counter is incremented when used as an Int
  arg Counter c; arg Int i
  implicit
  i := c start
  (addressof c:start) map Int += 1

function make_counter -> counter
  arg Link:Counter counter
  counter :> new Counter

var Link:Counter counter :> counter_maker
for (var Int i) 0 5
  var Int value := counter; console value eol
#-----------------------------
var Link:Counter counter1 :> counter_maker
var Link:Counter counter2 :> counter_maker

for (var Int i) 0 5
  var Int value := counter1; console value eol

console (cast counter1 Int) " " (cast counter2 Int) eol
0
1
2
3
4
5 0
#-----------------------------

# ^^PLEAC^^_11.5
#-----------------------------
scalar_ref :> scalar         # get reference to named scalar
#-----------------------------
console scalar_ref           # dereference it
scalar_ref := 23             # alter referent's value
#-----------------------------
function new_anon_scalar -> s
  arg Link:Int s
  s :> new Int
#-----------------------------
sref :> new_anon_scalar
sref := 3
console "Three = " sref eol
#-----------------------------------

# @@PLEAC@@_17.0
module "/pliant/language/os/socket.pli"         # for low level socket calls
module "/pliant/language/stream/tcp.pli"        # for TCP streams
module "/pliant/protocol/common/tcp_server.pli" # for server writing
#-------------------------------


# @@PLEAC@@_17.1
module "/pliant/language/stream.pli"
module "/pliant/protocol/stream/tcp.pli"
(var Stream s) open "tcp://thehost/client/port" in+out+safe
if s=failure
  console "connection failed" eol
  #...
# write a line on the stream
s writeline "Why don't you call me anymore?\n";
# read a line
var Str answer := s readline
# terminate
s close
#-------------------------------


# @@PLEAC@@_17.2
module "/pliant/language/stream.pli"
module "/pliant/protocol/common/tcp_server.pli"

type MyServer
  tcp_fields "My Server" server_port
  
TcpServer maybe MyServer

method server service gstream
  arg_rw GeneralServer server ; arg_rw Stream stream
  # get the ip of the connected client
  var Str from_ip := gstream query "remote_ip_address"
  # handle the connection (discussion through stream)

# if you want to check some things at start time

method server start_checkup -> status
  arg_rw MyServer server ; arg Status status
  # check whatever you want
  return success

# if you want to perform actions at shutdown

method server stop_checkup
  arg_rw MyServer server
  # do whatever you need
  
# create a server
define_tcp_server MyServer my_server

# run the server detached
my_server detached
#---------------------------------


# @@PLEAC@@_17.4
module "/pliant/language/stream/stream.pli"
module "/pliant/language/stream/udp.pli"
# open connection
(var Stream s) open "udp://the_host/client/port" in+out+safe
# configure priority
s configure "priority high"
# configure timeout
s configure "timeout 10"
# write something
s writeline "hello!"
# read in buffer what is available
s read_available buffer_adr buffer_size
#-------------------------------


# @@PLEAC@@_17.5
module "/pliant/language/stream.pli"
module "/pliant/language/stream/udp.pli"

# almost the pliant DNS UDP server implementation:

thread
  part udp_server "UDP server" # 'part' is used for administration monitoring
    (var Stream s) open "udp:/server/53" in+out+safe
    s configure "priority high"
    while not server:please_stop_udp
      part wait_for_request "wait for UDP request"
        s read_available (var Address adr) (var Int size)  # read the request
        part answer_request "answer UDP request"
          server answer adr size s true                    # answer the request
        part reset_stream "reset UDP stream"
          s configure "reset"
        if s:is_crashed
          console "UDP stream crashed !  Restarting it." eol
          s open "udp:/server/53" in+out+safe
          s configure "priority high"
      server please_stop_udp := false
#-------------------------------