Enhanced Expression Syntax

Keith Vetter 2018-09-26: Another tip I've always wished was implemented is tip 282: Enhanced Expression Syntax . It proposes enhancing the syntax for expr to allow for both assignment and multiple statements.

It's been debated several times on the tcl-core mailing list--here's a thread from 2017-02. IIRC, everyone thought it was a nice idea but there's some issues over how this plays with lvalues and arrays.

Be that as it may, here's a tcl-only implementation of tip-282.

proc math {expr} {
    set value ""
    set statements [split $expr ";\n"]
    foreach statement $statements {
        set statement [string trim $statement]
        if {$statement eq ""} continue
        set n [regexp {^(\S+)\s*=\s*(.*)} $statement . var m]
        if {! $n} { error "cannot parse $statement" }
        set value [uplevel 1 set $var \[expr \{$m\}\]]
        # puts "DEBUG: set $var \[expr \{$m\}\] <== $value"
    }
    return $value
}

# Sample usages

# Pythagoras
lassign {0 0 3 4} x0 y0 x1 y1
math {
    dx = ($x1 - $x0);
    dy = ($y1 - $y0);
    len = hypot($dx, $dy)
}
puts "dx: $dx  dy: $dy  len: $len"

# Example from the tip-282 page
lassign {3 4} y z
math {
    x = 5 * $y + 6 * $z;
    w = $x**2 + $y**2;
    v = $w**2 + $y**2;
}

# Parsing timestamps
set totalSeconds [expr {11 + 12*60 + 13*60*60 + 14*60*60*24}]
math {
    seconds      = $totalSeconds % 60;
    totalMinutes = $totalSeconds / 60;
    minutes      = $totalMinutes % 60;
    totalHours   = $totalMinutes / 60;
    hours        = $totalHours   % 24;
    days         = $totalHours   / 24;
}
puts "days: $days   hours: $hours   minutes: $minutes   seconds: $seconds"

aplsimple - 2018-09-28 13:45:18

It was passed over modestly:)) but there are another smart features of your code:

 - expressions may be divided with "\n"
 - ";" is superfluous at the end of line
 - expressions piled into a line are divided with ";"
 - spaces may be omitted everywhere

e.g.

 % set totalSeconds [expr {11 + 12*60 + 13*60*60 + 14*60*60*24}]
 ==> 1257131
 % math {
    seconds      = $totalSeconds % 60
    totalMinutes = $totalSeconds / 60;
    minutes      = $totalMinutes % 60
 totalHours=$totalMinutes/60;hours=$totalHours%24
    days         = $totalHours   / 24
 }
 ==> 14
 % puts "days: $days   hours: $hours   minutes: $minutes   seconds: $seconds"
 ==> days: 14   hours: 13   minutes: 12   seconds: 11