runtime.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. // Copyright 2023 The Knuth Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package knuth // modernc.org/knuth
  5. import (
  6. "fmt"
  7. "io"
  8. "math"
  9. "os"
  10. "strings"
  11. "unsafe"
  12. )
  13. var (
  14. _ File = (*binaryFile)(nil)
  15. _ File = (*textFile)(nil)
  16. _ File = (*poolFile)(nil)
  17. _ error = Error("")
  18. )
  19. // Error is a specific error implementation.
  20. type Error string
  21. func (e Error) Error() string { return string(e) }
  22. // WriteWidth is the type of width in `writeln(foo: width);`.
  23. type WriteWidth int
  24. // File represents a Pascal file.
  25. type File interface {
  26. ByteP() *byte
  27. Close()
  28. CurPos() int32
  29. Data4P() *[4]byte
  30. EOF() bool
  31. EOLN() bool
  32. ErStat() int32
  33. Get()
  34. Put()
  35. Read(args ...interface{})
  36. Readln(args ...interface{})
  37. Reset(args ...interface{})
  38. Rewrite(args ...interface{})
  39. SetPos(int32)
  40. Write(args ...interface{})
  41. Writeln(args ...interface{})
  42. }
  43. type file struct {
  44. buf []byte
  45. name string
  46. r io.Reader
  47. r0 io.Reader
  48. reset func(string) (io.Reader, error)
  49. w io.Writer
  50. w0 io.Writer
  51. atEOF bool
  52. atEOLN bool
  53. erStat int32
  54. isText bool
  55. }
  56. func (f *file) ByteP() *byte {
  57. f.boot()
  58. return &f.buf[0]
  59. }
  60. func (f *file) Data4P() *[4]byte {
  61. f.boot()
  62. return (*[4]byte)(unsafe.Pointer(&f.buf[0]))
  63. }
  64. func (f *file) boot() {
  65. if len(f.buf) == 0 {
  66. f.buf = f.buf[:cap(f.buf)]
  67. f.Get()
  68. }
  69. }
  70. func (f *file) Put() {
  71. panic(todo(""))
  72. }
  73. func (f *file) EOLN() bool {
  74. if !f.isText {
  75. panic(todo(""))
  76. }
  77. f.boot()
  78. return f.atEOLN || f.atEOF
  79. }
  80. func (f *file) ErStat() int32 {
  81. return f.erStat
  82. }
  83. func (f *file) Close() {
  84. if f.r0 != nil {
  85. if x, ok := f.r0.(io.Closer); ok {
  86. x.Close()
  87. }
  88. f.r0 = nil
  89. }
  90. if f.r != nil {
  91. f.erStat = 0
  92. if x, ok := f.r.(io.Closer); ok {
  93. if err := x.Close(); err != nil {
  94. f.erStat = 1
  95. }
  96. }
  97. f.r = nil
  98. }
  99. if f.w0 != nil {
  100. if x, ok := f.w.(io.Closer); ok {
  101. x.Close()
  102. }
  103. f.w0 = nil
  104. }
  105. if f.w != nil {
  106. f.erStat = 0
  107. if x, ok := f.w.(io.Closer); ok {
  108. if err := x.Close(); err != nil {
  109. f.erStat = 1
  110. }
  111. }
  112. f.w = nil
  113. }
  114. }
  115. func (f *file) EOF() bool {
  116. f.boot()
  117. return f.atEOF
  118. }
  119. func (f *file) Read(args ...interface{}) {
  120. if f.r == nil && f.r0 != nil {
  121. f.r = f.r0
  122. f.r0 = nil
  123. }
  124. f.boot()
  125. switch len(f.buf) {
  126. case 1:
  127. for _, v := range args {
  128. switch x := v.(type) {
  129. case *byte:
  130. *x = f.buf[0]
  131. default:
  132. panic(todo("%T", x))
  133. }
  134. f.Get()
  135. }
  136. default:
  137. panic(todo("", len(f.buf)))
  138. }
  139. }
  140. func (f *file) Get() {
  141. if f.atEOF {
  142. panic(todo(""))
  143. }
  144. f.atEOLN = false
  145. if c, err := f.r.Read(f.buf[:]); c != len(f.buf) {
  146. if err != io.EOF {
  147. panic(todo(""))
  148. }
  149. f.atEOLN = true
  150. f.atEOF = true
  151. return
  152. }
  153. if f.isText && f.buf[0] == '\n' {
  154. f.atEOLN = true
  155. f.buf[0] = ' '
  156. }
  157. }
  158. func (f *file) Readln(args ...interface{}) {
  159. f.Read(args...)
  160. for !f.EOLN() {
  161. f.Get()
  162. }
  163. f.Get()
  164. }
  165. func (f *file) Reset(args ...interface{}) {
  166. if debug {
  167. defer func() {
  168. trc("RESET %p %q %v -> erStat %v (%v: %v:)", f, f.name, args, f.erStat, origin(3), origin(4))
  169. }()
  170. }
  171. f.atEOF = false
  172. f.atEOLN = false
  173. f.buf = f.buf[:0]
  174. switch len(args) {
  175. case 0:
  176. if f.r == nil && f.r0 != nil {
  177. f.r = f.r0
  178. f.r0 = nil
  179. break
  180. }
  181. switch x, ok := f.r.(io.Seeker); {
  182. case ok:
  183. if _, err := x.Seek(0, io.SeekStart); err != nil {
  184. panic(todo(""))
  185. }
  186. default:
  187. panic(todo(""))
  188. }
  189. case 1:
  190. switch x := args[0].(type) {
  191. case string:
  192. f.open(strings.TrimRight(x, " "))
  193. default:
  194. panic(todo("%T", x))
  195. }
  196. case 2:
  197. switch x := args[0].(type) {
  198. case string:
  199. switch y := args[1].(type) {
  200. case string:
  201. switch {
  202. case x == "TTY:" && y == "/O/I" && f.r0 != nil:
  203. f.name = x + y
  204. f.r = f.r0
  205. f.r0 = nil
  206. case y == "/O":
  207. f.open(strings.TrimRight(x, " "))
  208. default:
  209. panic(todo("%q %q %v", x, y, f.w != nil))
  210. }
  211. default:
  212. panic(todo("%T", y))
  213. }
  214. default:
  215. panic(todo("%T", x))
  216. }
  217. default:
  218. panic(todo("", args, len(args)))
  219. }
  220. }
  221. func (f *file) open(name string) {
  222. if f.reset != nil {
  223. if x, ok := f.r.(io.Closer); ok {
  224. x.Close()
  225. f.r = nil
  226. }
  227. f.name = name
  228. f.atEOF = false
  229. f.atEOLN = false
  230. f.erStat = 0
  231. var err error
  232. f.r, err = f.reset(name)
  233. if err == nil {
  234. return
  235. }
  236. f.r = nil
  237. f.erStat = 1
  238. return
  239. }
  240. f.name = name
  241. f.atEOF = false
  242. f.atEOLN = false
  243. f.erStat = 0
  244. var err error
  245. f.r, err = os.Open(name)
  246. if err == nil {
  247. return
  248. }
  249. f.r = nil
  250. f.erStat = 1
  251. }
  252. func (f *file) Rewrite(args ...interface{}) {
  253. if debug {
  254. defer func() {
  255. trc("REWRITE %p %q %v -> erStat %v ()", f, f.name, args, f.erStat)
  256. }()
  257. }
  258. f.atEOF = true
  259. f.atEOLN = false
  260. switch len(args) {
  261. case 0:
  262. if f.w == nil && f.w0 != nil {
  263. f.w = f.w0
  264. f.w0 = nil
  265. break
  266. }
  267. panic(todo(""))
  268. case 2:
  269. switch x := args[0].(type) {
  270. case string:
  271. switch y := args[1].(type) {
  272. case string:
  273. switch {
  274. case x == "TTY:" && y == "/O" && f.w0 != nil:
  275. f.name = x + y
  276. f.w = f.w0
  277. f.w0 = nil
  278. case y == "/O":
  279. f.erStat = 0
  280. if f.w != nil {
  281. panic(todo(""))
  282. }
  283. var err error
  284. f.name = strings.TrimRight(x, " ")
  285. if f.w, err = os.Create(f.name); err != nil {
  286. f.w = nil
  287. f.erStat = 1
  288. break
  289. }
  290. default:
  291. panic(todo("%q %q", x, y))
  292. }
  293. default:
  294. panic(todo("%T", y))
  295. }
  296. default:
  297. panic(todo("%T", x))
  298. }
  299. default:
  300. panic(todo("", args, len(args)))
  301. }
  302. }
  303. func (f *file) CurPos() int32 {
  304. switch {
  305. case f.r != nil:
  306. s, ok := f.r.(io.ReadSeeker)
  307. if !ok {
  308. panic(todo(""))
  309. }
  310. n, err := s.Seek(0, io.SeekCurrent)
  311. if err != nil || n > math.MaxInt32 {
  312. panic(todo(""))
  313. }
  314. return int32(n)
  315. case f.w != nil:
  316. panic(todo(""))
  317. default:
  318. panic(todo(""))
  319. }
  320. }
  321. func (f *file) SetPos(n int32) {
  322. switch {
  323. case f.r != nil:
  324. s, ok := f.r.(io.ReadSeeker)
  325. if !ok {
  326. panic(todo(""))
  327. }
  328. switch {
  329. case n < 0:
  330. if _, err := s.Seek(0, io.SeekEnd); err != nil {
  331. panic(todo(""))
  332. }
  333. f.atEOF = true
  334. default:
  335. if _, err := s.Seek(int64(n), io.SeekStart); err != nil {
  336. panic(todo(""))
  337. }
  338. f.atEOF = false
  339. f.atEOLN = false
  340. f.Get()
  341. }
  342. case f.w != nil:
  343. panic(todo(""))
  344. default:
  345. panic(todo(""))
  346. }
  347. }
  348. type textFile struct {
  349. *file
  350. }
  351. // NewTextFile returns File suitable for Pascal file type 'text'.
  352. func NewTextFile(r io.Reader, w io.Writer, open func(string) (io.Reader, error)) File {
  353. return &textFile{
  354. &file{
  355. buf: make([]byte, 1),
  356. isText: true,
  357. r0: r,
  358. reset: open,
  359. w0: w,
  360. },
  361. }
  362. }
  363. func (f *textFile) Write(args ...interface{}) {
  364. if f.w == nil && f.w0 != nil {
  365. f.w = f.w0
  366. f.w0 = nil
  367. }
  368. var a [][]interface{}
  369. for i := 0; i < len(args); i++ {
  370. switch x := args[i].(type) {
  371. case WriteWidth:
  372. a[len(a)-1] = append(a[len(a)-1], int(x))
  373. default:
  374. a = append(a, []interface{}{x})
  375. }
  376. }
  377. for _, v := range a {
  378. switch x := v[0].(type) {
  379. case string:
  380. switch len(v) {
  381. case 1:
  382. if _, err := fmt.Fprintf(f.w, "%s", x); err != nil {
  383. panic(todo("", err))
  384. }
  385. case 2:
  386. if _, err := fmt.Fprintf(f.w, "%*s", v[1], v[0]); err != nil {
  387. panic(todo("", err))
  388. }
  389. default:
  390. panic(todo("", v))
  391. }
  392. case uint8:
  393. switch len(v) {
  394. case 1:
  395. if _, err := fmt.Fprintf(f.w, "%d", v[0]); err != nil {
  396. panic(todo("", err))
  397. }
  398. case 2:
  399. if _, err := fmt.Fprintf(f.w, "%*d", v[1], v[0]); err != nil {
  400. panic(todo("", err))
  401. }
  402. default:
  403. panic(todo("", v))
  404. }
  405. case uint16:
  406. switch len(v) {
  407. case 1:
  408. if _, err := fmt.Fprintf(f.w, "%d", v[0]); err != nil {
  409. panic(todo("", err))
  410. }
  411. case 2:
  412. if _, err := fmt.Fprintf(f.w, "%*d", v[1], v[0]); err != nil {
  413. panic(todo("", err))
  414. }
  415. default:
  416. panic(todo("", v))
  417. }
  418. case int32, int:
  419. switch len(v) {
  420. case 1:
  421. if _, err := fmt.Fprintf(f.w, "%d", v[0]); err != nil {
  422. panic(todo("", err))
  423. }
  424. case 2:
  425. if _, err := fmt.Fprintf(f.w, "%*d", v[1], v[0]); err != nil {
  426. panic(todo("", err))
  427. }
  428. default:
  429. panic(todo("", v))
  430. }
  431. case float32:
  432. switch len(v) {
  433. case 1:
  434. if _, err := fmt.Fprintf(f.w, "%g", v[0]); err != nil {
  435. panic(todo("", err))
  436. }
  437. case 2:
  438. if _, err := fmt.Fprintf(f.w, "%*e", v[1], v[0]); err != nil {
  439. panic(todo("", err))
  440. }
  441. case 3:
  442. mw := v[1].(int)
  443. nw := v[2].(int)
  444. if _, err := fmt.Fprintf(f.w, "%*.*f", mw, nw, v[0]); err != nil {
  445. panic(todo("", err))
  446. }
  447. default:
  448. panic(todo("", v))
  449. }
  450. case float64:
  451. switch len(v) {
  452. case 1:
  453. if _, err := fmt.Fprintf(f.w, "%g", v[0]); err != nil {
  454. panic(todo("", err))
  455. }
  456. case 2:
  457. if _, err := fmt.Fprintf(f.w, "%*e", v[1], v[0]); err != nil {
  458. panic(todo("", err))
  459. }
  460. case 3:
  461. mw := v[1].(int)
  462. nw := v[2].(int)
  463. if _, err := fmt.Fprintf(f.w, "%*.*f", mw, nw, v[0]); err != nil {
  464. panic(todo("", err))
  465. }
  466. default:
  467. panic(todo("", v))
  468. }
  469. default:
  470. panic(todo("%T %v", x, v))
  471. }
  472. }
  473. }
  474. func (f *textFile) Writeln(args ...interface{}) {
  475. f.Write(args...)
  476. if _, err := fmt.Fprintln(f.w); err != nil {
  477. panic(todo("", err))
  478. }
  479. }
  480. type binaryFile struct {
  481. *file
  482. }
  483. // NewBinaryFile returns a File suitable for Pascal file type 'file of T'.
  484. func NewBinaryFile(r io.Reader, w io.Writer, sizeofT int, open func(string) (io.Reader, error)) File {
  485. return &binaryFile{
  486. &file{
  487. buf: make([]byte, sizeofT),
  488. r0: r,
  489. reset: open,
  490. w0: w,
  491. },
  492. }
  493. }
  494. func (f *binaryFile) Write(args ...interface{}) {
  495. switch len(f.buf) {
  496. case 1:
  497. for _, v := range args {
  498. switch x := v.(type) {
  499. case int32:
  500. f.buf[0] = byte(x)
  501. case int:
  502. f.buf[0] = byte(x)
  503. case byte:
  504. f.buf[0] = x
  505. case int16:
  506. f.buf[0] = byte(x)
  507. case uint16:
  508. f.buf[0] = byte(x)
  509. default:
  510. panic(todo("%T", x))
  511. }
  512. f.Put()
  513. }
  514. default:
  515. panic(todo("", len(f.buf)))
  516. }
  517. }
  518. func (f *binaryFile) Put() {
  519. if c, err := f.w.Write(f.buf[:]); c != len(f.buf) {
  520. panic(todo("", err))
  521. }
  522. }
  523. func (f *binaryFile) Writeln(args ...interface{}) {
  524. panic(todo(""))
  525. }
  526. type poolFile struct {
  527. *file
  528. }
  529. // NewPoolFile returns a read only File with a string pool.
  530. func NewPoolFile(pool string) File {
  531. return &poolFile{
  532. &file{
  533. buf: make([]byte, 1),
  534. isText: true,
  535. r: strings.NewReader(pool),
  536. },
  537. }
  538. }
  539. func (f *poolFile) Close() {
  540. f.atEOF = true
  541. }
  542. func (f *poolFile) ErStat() int32 {
  543. return 0
  544. }
  545. func (f *poolFile) Reset(args ...interface{}) {
  546. f.atEOF = false
  547. f.atEOLN = false
  548. switch len(args) {
  549. case 2: // eg. ["MFbases:MF.POOL", "/O"]
  550. f.r.(*strings.Reader).Seek(0, io.SeekStart)
  551. f.Get()
  552. default:
  553. panic(todo("%v", args))
  554. }
  555. }
  556. func (f *poolFile) Write(args ...interface{}) {
  557. panic(todo(""))
  558. }
  559. func (f *poolFile) Writeln(args ...interface{}) {
  560. panic(todo(""))
  561. }