diff keiko/util.tcl @ 0:bfdcc3820b32

Basis
author Mike Spivey <mike@cs.ox.ac.uk>
date Thu, 05 Oct 2017 08:04:15 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keiko/util.tcl	Thu Oct 05 08:04:15 2017 +0100
@@ -0,0 +1,149 @@
+#
+# util.tcl
+# 
+# This file is part of the Oxford Oberon-2 compiler
+# Copyright (c) 2006--2016 J. M. Spivey
+# All rights reserved
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+#    this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# max -- maximum of any number of args
+proc max {x args} {
+    set max $x
+    foreach y $args {
+        if {$y > $max} {set max $y}
+    }
+    return $max
+}
+
+# count -- number of occurrences of a char in a string
+proc count {ch s} {return [regsub -all $ch $s "" dummy]}
+
+# lmember -- test for list membership
+proc lmember {x xs} {
+    return [expr {[lsearch -exact $xs $x] >= 0}]
+}
+
+# ladd -- add values to a set
+proc ladd {sv args} {
+    upvar $sv s
+
+    foreach x $args {
+        if {! [lmember $x $s]} {lappend s $x}
+    }
+}
+
+# lsplit -- split a list into components
+proc lsplit {xs args} {
+    set n [llength $args]
+
+    if {[llength $xs] != $n} {
+        error "expected $n fields, got [llength $xs]"
+    }
+
+    for {set i 0} {$i < $n} {incr i} {
+        uplevel [list set [lindex $args $i] [lindex $xs $i]]
+    }
+}
+
+# with -- bind names to record fields in body
+proc with {record fields body} {
+    uplevel [concat [list lsplit $record] $fields]
+    uplevel $body
+}
+
+# filter -- filter a list by a predicate
+proc filter {p xs} {
+    set ys {}
+    foreach x $xs {if {[uplevel $p $x]} {lappend ys $x}}
+    return $ys
+}
+
+# exists -- test is a list has any member that satisfies a predicate
+proc exists {p xs} {
+    foreach x $xs {if {[uplevel $p $x]} {return 1}}
+    return 0
+}
+
+# map -- apply a function to all elements of a list
+proc map {f xs} {
+    set ys {}
+    foreach x $xs {lappend ys [uplevel [concat $f [list $x]]]}
+    return $ys
+}
+
+# flatmap -- apply a function to all elements of a list, concatenate results
+proc flatmap {f xs} {
+    set ys {}
+    foreach x $xs {set ys [concat $ys [uplevel $f $x]]}
+    return $ys
+}
+
+# remdups -- remove adjecent duplicates from a list
+proc remdups {xs} {
+    if {$xs == ""} {
+        return {}
+    } else {
+        set y [lindex $xs 0]
+        set ys [list $y]
+        foreach x $xs {
+            if {$x != $y} {lappend ys $x}
+            set y $x
+        }
+        return $ys
+    }
+}
+
+# nth_char -- return n'th character of string
+proc nth_char {n string} {
+    return [string index $string $n]
+}
+
+# nth_char_is -- test if n'th character of string is a given char
+proc nth_char_is {n ch string} {
+    return [expr {[string index $string $n] == $ch}]
+}
+
+# trycatch -- handle exceptions by evaluating alternative script
+proc trycatch {s1 s2} {
+    if {[catch {uplevel $s1}]} {uplevel $s2}
+}
+
+set charcode() 0
+for {set i 1} {$i < 128} {incr i} {
+    set ch [format "%c" $i]
+    set charcode($ch) $i
+}
+
+# trim -- trim leading and trailing spaces
+proc trim {s} { regexp {^ *(.*[^ ]) *$} $s dummy s; return $s }
+
+# csym -- make C symbol
+proc csym {k s} {
+    if {$k == ""} {
+        return [regsub "\\." $s ""]
+    } else {
+        return ${k}_[regsub "\\." $s ""]
+    }
+}