crypt of decay - нет никакого бага. увы. [entries|archive|friends|userinfo]
ketmar

[ userinfo | ljr userinfo ]
[ archive | journal archive ]

нет никакого бага. увы. [Oct. 8th, 2012|01:32 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
баг в jim-tcl — как обычно — оказался всего лишь иллюзией. конечно, кривокоду немало поспособствовала подробнейшая документация по API. зато маинтайнер отозвался оперативно, дал пару хинтов и баг был с особым садизмом растоптан.

а ещё в UI появились lineedit'ы, scrollbar'ы и listbox'ы. и вся эта красотища рулится прямиком из tcl, примерно так:
  set win [winsys window red win0 $::win_x $::win_y 180 120 title]
  set ok [$win button ok 2 $([$win geth]-9-12) -1 -1 O&K [lambda {me} {
    set win [$me window]
    puts [[$win findbyid cb1] getstate]
    puts [[$win findbyid led0] gettext]
  }]]
  $ok setdefault
  $ok activate
  #
  set st [$win static static_name 2 2 -1 -1 {&name:}]
  #
  set le [$win lineedit led0 $([$st getx]+[$st getw]+2) [$st gety] 60 -1 text]
  $st setlinked $le
  #
  set cb1 [$win checkbox cb1 [$st getx] $([$st gety]+[$st geth]+1) -1 -1 {checkbox &1}]
  $cb1 setstate 1
и тому подобное. с няшным «типа объектным» API.
Linkmeow!

Comments:
From:(Anonymous)
Date:October 8th, 2012 - 12:57 pm
(Link)
Не, ну какой же всё-таки tcl наркоманский.
[User Picture]
From:[info]ketmar
Date:October 8th, 2012 - 01:04 pm
(Link)
неа, на самом деле простой, как три копейки. форт чем-то напоминает. и лисп. тут ещё стоит учесть, что «так никто не делит пышки», по уму надо бы сделать layouter, и оно будет покрасивей. собственно, достаточно знать про [] и {}. ну, и сахар в виде $(...), что на самом деле не более чем [expr ...].

хотя если идти ещё глубже, то $a тоже сахар, который на самом деле [set a].

а ещё всё это можно обернуть в макросы, и станет совсем приятно.
From:(Anonymous)
Date:October 8th, 2012 - 07:49 pm
(Link)
Хм, а ты меня прям заинтересовал tcl-ем. Пойду обмажусь несвежими мануалами.
[User Picture]
From:[info]ketmar
Date:October 9th, 2012 - 07:13 am
(Link)
вот так вот выглядит более-менее окончательный вариант описания морды, например:
set win_x 0
set win_y 0

set win [ \
   window: {
    scheme: red
    id: win1
    id: win0
    title: mytitle
    position: {$::win_x $::win_y}
    size: {180 120}
    margins: {2 1}
    #
    static: {
      id: static0
      caption: "&name:"
      position: {2 2}
    }
    #
    lineedit: {
      id: led0
      position: {after static0}
      width: 60
      text: "text"
      linked-from: static0
    }
    #
    checkbox: {
      id: cb1
      caption: "checkbox &1"
      position: {under static0}
      #state: 1
      checked
    }
    #
    checkbox: {
      id: cb2
      caption: "checkbox &2"
      position: {under cb1}
      #state: 2
      question
    }
    #
    radio: {
      group: rgroup1
      id: g1r1
      caption: "r&adio 1"
      position: { {{x cb2} + 4}  {{under cb2} + 11} }
    }
    #
    radio: {
      group: rgroup1
      id: g1r2
      caption: "ra&dio 2"
      position: {under g1r1}
      radioactive
    }
    #
    frame: {
      id: frm
      caption: frame
      #framebox sets both position and size
      framebox: g1r1 g1r1
    }
    #
    scrollbar: {
      horiz
      id: hsb
      position: { {{x g1r1}}  {{y frm} + {height frm} + 4} }
      size: 64
    }
    #
    scrollbar: {
      vert
      id: vsb
      position: { {{x hsb} + {width hsb} + 4}  {{y hsb} - 32} }
      size: 60
      max: 32
      pos: 6
    }
    #
    listbox: {
      id: lsb
      position: {100 10}
      size: {60 90}
      vbar
      multi
      items: {
        "xitem 0"
        "xitem 1"
      }
    }
    #
    button: {
      id: ok
      caption: O&K
      position: {2  {{height window} - 9 - 12}}
      onclick: {
        set win [$me window]
        puts "=== OK ==="
        puts [$me type]
        puts [$win type]
        puts "<$me>"
        puts "<$win>"
        #
        puts "cb1: [[$win cb1] getstate]"
        puts "cb2: puts [[$win cb2] getstate]"
        puts "radiogroup 'rgroup1': [$win getradioactive rgroup1]"
        puts "g1r1 group: [[$win g1r1] getgroup]"
        puts "g1r1: [[$win g1r1] getradioactive]"
        puts "g1r2: [[$win g1r2] getradioactive]"
        puts "edt: \[[[$win led0] gettext]\]"
      }
      default
      active
    }
    #
    button: {
      id: cancel
      caption: Cancel
      position: {after ok}
      onclick: {
        set win [$me window]
        puts "=== CANCEL ==="
        puts [$me type]
        puts [$win type]
        [$me window] close
      }
      cancel
    }
   }]
#
set lsb [$win lsb]
loop ic 0 22 {
  $lsb additem "item $ic"
}

[User Picture]
From:[info]ketmar
Date:October 9th, 2012 - 07:16 am
(Link)
а, да. «парзер» этой байды написан опять же на самом tcl. и в итоге он преобразует описание в вызовы, которые показаны в посте. естественно, парзер активно пользуется фичами типа namespaces и eval. тут не видно, но в принципе в математике можно использовать локальные переменные, объявленые до window.
[User Picture]
From:[info]ketmar
Date:October 8th, 2012 - 01:11 pm
(Link)
можно, например, такое напилить:
window {
  scheme: red
  id: win0
  title: mytitle
  position: {$::win_x $::win_y}
  size: {180 120}
  margins: {2 2}
  button: {
    id: ok
    position: {2 $(window height-9-12)}
    caption: O&K
    onclick: [lambda {me} { ... }]
    default
    active
  }
  button: {
    id: cancel
    caption: Cancel
    position: {right-of ok}
    onclick: [lambda {me} { [[me window] close] }]
    cancel
  }
  ... и так далее
}


вполне себе декларативное описание интерфейса, и тем не менее это по-прежнему tcl.
From:[info]tzirechnoy.livejournal.com
Date:October 8th, 2012 - 07:26 pm
(Link)
А какую ты лямбду конкретно сделал?
[User Picture]
From:[info]ketmar
Date:October 8th, 2012 - 11:57 pm
(Link)
а это не стандартный tcl, это jim-tcl: там lambda вмонтирована в язык. на самом деле это просто анонимная (ну, почти; со сгенерённым труднропроизносимым именем, на который реагирует GC и может такие объекты собрать, когда они больше не нужны) функция с параметрами.

в «обычном» tcl, полагаю, для этого нужно будет делать какую-нибудь хитрую магию, чтобы не засирать пространство имён команд.
From:[info]tzirechnoy.livejournal.com
Date:October 9th, 2012 - 01:38 pm
(Link)
Ну да в общем, нетривиально.

То есть, у меня пока висит тривиальное

proc peval {lbody args} {
  eval $lbody
}
proc lambda {body args} {
  return [concat [list peval $body] $args]
}


И не засирает, понятно, но ему нужэн eval для работы:
set a [lambda {puts [lindex $args 0]}]; eval $a

Мне для всяких command к Tk-кнопкам хватает, да и свой код подгоняю.
По идее, можно через unknown сделать, чтобы оно и для общего случая работало.
Ну и, скорость, надо думать, будет аховой.
From:[info]tzirechnoy.livejournal.com
Date:October 9th, 2012 - 01:38 pm
(Link)
Ну да в общем, нетривиально.

То есть, у меня пока висит тривиальное

proc peval {lbody args} {
  eval $lbody
}
proc lambda {body args} {
  return [concat [list peval $body] $args]
}


И не засирает, понятно, но ему нужэн eval для работы:
set a [lambda {puts [lindex $args 0]}]; eval $a

Мне для всяких command к Tk-кнопкам хватает, да и свой код подгоняю.
По идее, можно через unknown сделать, чтобы оно и для общего случая работало но лень -- строчек пять ведь писать, наверное).
Ну и, скорость, надо думать, будет аховой.
[User Picture]
From:[info]ketmar
Date:October 9th, 2012 - 01:46 pm
(Link)
тоже вариант. у jim там читерство: автор добавил тип ref с финализатором, который может хранить именно то, что и написано — ссылку. и когда ref сдыхает, движок зовёт gc и убивает кого надо.
# Creates an anonymous procedure
proc lambda {arglist args} {
	tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args
}

proc lambda.finalizer {name val} {
	rename $name {}
}

но меня устраивает — учитывая, что я просто таскаю с собой весь Jim, — можно читерить направо и налево.