# -*- pliant -*-
# @@PLEAC@@_NAME
# @@SKIP@@ Pliant
# @@PLEAC@@_WEB
# @@SKIP@@ http://pliant.cx
# @@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
#-------------------------------