; Tcl parser — thin layer over tcl-tokenize
; Adds tcl-parse entry point and word utility fns

; Entry point: parse Tcl source to a list of commands.
; Returns same structure as tcl-tokenize.
(define tcl-parse (fn (src) (tcl-tokenize src)))

; True if word has no substitutions — value can be read statically.
; braced words are always simple. compound words are simple when all
; parts are plain text with no var/cmd parts.
(define tcl-word-simple?
  (fn (word)
    (cond
      ((= (get word :type) "braced") true)
      ((= (get word :type) "compound")
        (let ((parts (get word :parts)))
          (every? (fn (p) (= (get p :type) "text")) parts)))
      (else false))))

; Concatenate text parts of a simple word into a single string.
; For braced words returns :value directly.
; For compound words with only text parts, joins them.
; Returns nil for words with substitutions.
(define tcl-word-literal
  (fn (word)
    (cond
      ((= (get word :type) "braced") (get word :value))
      ((= (get word :type) "compound")
        (if (tcl-word-simple? word)
          (join "" (map (fn (p) (get p :value)) (get word :parts)))
          nil))
      (else nil))))

; Number of words in a parsed command.
(define tcl-cmd-len
  (fn (cmd) (len (get cmd :words))))

; Nth word literal from a command (index 0 = command name).
; Returns nil if word has substitutions.
(define tcl-nth-literal
  (fn (cmd n) (tcl-word-literal (nth (get cmd :words) n))))
