# -*- 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 (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 #-------------------------------