;; lib/go/std/strconv.sx — Go's `strconv` package, v0 subset.

(define
  go-strconv-itoa
  ;; Itoa(n) → string. Real Go returns the decimal representation.
  (fn (args)
    (cond
      (not (= (len args) 1))
      (list :eval-error :strconv-itoa-arity (len args))
      :else
      (let ((n (first args)))
        (cond
          (not (number? n)) (list :eval-error :strconv-itoa-not-number n)
          :else (str n))))))

(define
  go-strconv-atoi
  ;; Atoi(s) → (int, error). v0 returns just the int on success or
  ;; an :eval-error on failure (multi-return is a later refinement).
  (fn (args)
    (cond
      (not (= (len args) 1))
      (list :eval-error :strconv-atoi-arity (len args))
      :else
      (let ((s (first args)))
        (cond
          (not (string? s)) (list :eval-error :strconv-atoi-not-string s)
          (= (len s) 0) (list :eval-error :strconv-atoi-empty)
          :else (go-strconv-parse-int s 0 (= (nth s 0) "-") 0))))))

(define
  go-strconv-parse-int
  ;; Parse a (possibly signed) base-10 integer literal. Stops on the
  ;; first non-digit char and returns the parsed prefix, or :eval-error
  ;; if no digits were consumed.
  (fn (s start neg acc)
    (let ((i (cond (= start 0) (cond neg 1 :else 0) :else start)))
      (cond
        (>= i (len s))
        (cond
          (= (cond neg (- i 1) :else i) 0)
          (list :eval-error :strconv-atoi-no-digits s)
          :else
          (cond neg (- 0 acc) :else acc))
        :else
        (let ((d (go-strconv-digit (nth s i))))
          (cond
            (< d 0)
            (cond
              (= (cond neg (- i 1) :else i) 0)
              (list :eval-error :strconv-atoi-no-digits s)
              :else
              (cond neg (- 0 acc) :else acc))
            :else
            (go-strconv-parse-int s (+ i 1) neg (+ (* acc 10) d))))))))

(define
  go-strconv-digit
  (fn (c)
    (cond
      (= c "0") 0  (= c "1") 1  (= c "2") 2  (= c "3") 3
      (= c "4") 4  (= c "5") 5  (= c "6") 6  (= c "7") 7
      (= c "8") 8  (= c "9") 9
      :else -1)))

(define
  go-std-strconv
  (list :go-package "strconv"
    (list
      (list "Itoa" (list :go-builtin-fn go-strconv-itoa))
      (list "Atoi" (list :go-builtin-fn go-strconv-atoi)))))
