Initial import of Flobnar version 0.1 revision 2011.1214.
catseye
10 years ago

0 | -> encoding: UTF-8 | |

1 | ||

2 | Flobnar | |

3 | ======= | |

4 | ||

5 | _Version 0.1, Chris Pressey, Oct 28 2011_ | |

6 | ||

7 | One day in September of 2011 -- though I'm not sure precisely which | |

8 | one -- marked Befunge-93's 18th birthday. That means that Befunge is | |

9 | now old enough to drink in its native land of Canada. | |

10 | ||

11 | To celebrate this, I thought I'd get Befunge-93 drunk to see what | |

12 | would happen. | |

13 | ||

14 | What happened was _Flobnar_, an esolang which is in many respects a | |

15 | functional dual of Befunge-93; most of the symbols have analogous | |

16 | meanings, but execution proceeds in a much more dataflow-like fashion. | |

17 | ||

18 | This document describes Flobnar with a series of examples, presented | |

19 | in the format of Falderal 0.4 tests. | |

20 | ||

21 | Concepts | |

22 | -------- | |

23 | ||

24 | A familiarity with Befunge-93 is assumed in this document. Also, | |

25 | some concepts need to be explained before the description of the | |

26 | examples will make much sense. | |

27 | ||

28 | Like Befunge-93, Flobnar programs are held in a playfield -- a | |

29 | two-dimensional Cartesian grid of cells, each of which contains a | |

30 | symbol. | |

31 | ||

32 | Any cell in a Flobnar playfield may be evaluated. The meaning of | |

33 | the evaluation of a cell depends on the symbol it contains. In the | |

34 | context of execution, this symbol is called a term. | |

35 | ||

36 | Except for the first term to be evaluated, all terms are "evaluated | |

37 | from" one of the four cardinal directions: north, south, east, and | |

38 | west. The direction provides context: a term may evaluate to a | |

39 | different value depending on what direction it is evaluated from. | |

40 | ||

41 | When we say something about "what the cell to the /d/ evaluates to", | |

42 | where /d/ is a direction, it is implied that that cell is evaluated | |

43 | from the direction opposite to /d/. So, "what the cell to the north | |

44 | evaluates to" means "what the cell to the north evaluates to, when | |

45 | evaluated from the south." | |

46 | ||

47 | In addition, when we say "what the cell on the other side evaluates | |

48 | to", we mean this to be relative to the direction the current term | |

49 | was evaluated from. So, if the term was evaluated from the east, | |

50 | the "cell on the other side" refers to the cell to the west, as | |

51 | evaluated from the east. | |

52 | ||

53 | Flobnar is not a purely functional language; it permits input and | |

54 | output, as well as self-modification, just like Befunge-93 does. | |

55 | For this reason, order of evaluation should be completely defined. | |

56 | ||

57 | Flobnar Tests | |

58 | ------------- | |

59 | ||

60 | -> Tests for functionality "Interpret Flobnar program" | |

61 | ||

62 | -> Functionality "Interpret Flobnar program" is implemented by | |

63 | -> Haskell function Flobnar:showRun | |

64 | ||

65 | Basics of Execution | |

66 | ------------------- | |

67 | ||

68 | Whereas in Befunge-93 `@` indicates a stopping point of the program, | |

69 | in Flobnar, `@` indicates the starting point. The program evaluates | |

70 | to whatever the `@` it contains evaluates to. The `@` evaluates to | |

71 | whatever is west of it evaluates to. | |

72 | ||

73 | | 4@ | |

74 | = Result: 4 | |

75 | ||

76 | The program must contain one and only one @. | |

77 | ||

78 | | 4 | |

79 | ? Program does not contain exactly one @ | |

80 | ||

81 | | 4@@ | |

82 | ? Program does not contain exactly one @ | |

83 | ||

84 | Simple Constant Data | |

85 | -------------------- | |

86 | ||

87 | As in Befunge-93, single digits evaluate to the common decimal | |

88 | interpretation of themselves as numbers. You've already seen this | |

89 | for 4, but it's true for all of them. | |

90 | ||

91 | | 0@ | |

92 | = Result: 0 | |

93 | ||

94 | | 1@ | |

95 | = Result: 1 | |

96 | ||

97 | | 2@ | |

98 | = Result: 2 | |

99 | ||

100 | | 3@ | |

101 | = Result: 3 | |

102 | ||

103 | | 5@ | |

104 | = Result: 5 | |

105 | ||

106 | | 6@ | |

107 | = Result: 6 | |

108 | ||

109 | | 7@ | |

110 | = Result: 7 | |

111 | ||

112 | | 8@ | |

113 | = Result: 8 | |

114 | ||

115 | | 9@ | |

116 | = Result: 9 | |

117 | ||

118 | Playfield Traversal | |

119 | ------------------- | |

120 | ||

121 | Whereas in Befunge-93 `><^v` change the direction of the motion | |

122 | of the IP, in Flobnar these characters evaluate to what the | |

123 | appropriate adjacent cell evaluates to: | |

124 | ||

125 | < evaluates to whatever is west of it evaluates to | |

126 | > evaluates to whatever is east of it evaluates to | |

127 | v evaluates to whatever is south of it evaluates to | |

128 | ^ evaluates to whatever is north of it evaluates to | |

129 | ||

130 | | 4<<<<<@ | |

131 | = Result: 4 | |

132 | ||

133 | | >>>>>v | |

134 | | ^ v | |

135 | | ^ 4 | |

136 | | ^<<<<@ | |

137 | = Result: 4 | |

138 | ||

139 | Also, ' ' (blank space) evaluates to whatever the cell on the other | |

140 | side of it evaluates to. So, for example, if evaluated from the | |

141 | south, it evaluates to what the north of it evaluates to. | |

142 | ||

143 | | 4 @ | |

144 | = Result: 4 | |

145 | ||

146 | | > v | |

147 | | | |

148 | | 4 | |

149 | | ^ @ | |

150 | = Result: 4 | |

151 | ||

152 | Cells which are not specified are considered to contain blank space. | |

153 | (In the example below, the two middle lines have nothing in them, not | |

154 | even blank space.) | |

155 | ||

156 | | v@ | |

157 | | | |

158 | | | |

159 | | 4 < | |

160 | = Result: 4 | |

161 | ||

162 | Like Befunge-93, there is toroidal wrapping of evaluation: if we try | |

163 | to evaluate something outside the bounds of the playfield, we end up | |

164 | evaluating whatever is directly on the other side of the playfield. | |

165 | Unlike Befunge-93, however, the bounds of the playfield are determined | |

166 | solely by the minimal bounding box that encompasses all the non-' ' | |

167 | terms in the playfield. | |

168 | ||

169 | | @4 | |

170 | = Result: 4 | |

171 | ||

172 | | v@ | |

173 | | < v | |

174 | | ^< | |

175 | | 4 | |

176 | = Result: 4 | |

177 | ||

178 | There's a "Bridge" term, similar to Befunge's `#` instruction. It | |

179 | evaluates to whatever is one cell past the other side of it. | |

180 | ||

181 | | 5 6#@ | |

182 | = Result: 5 | |

183 | ||

184 | | 7v @ | |

185 | | v8#< | |

186 | | >#9 v | |

187 | | >^ | |

188 | | ^ < | |

189 | = Result: 7 | |

190 | ||

191 | And `#` is compatible with wrapping. | |

192 | ||

193 | | #@ 56 | |

194 | = Result: 5 | |

195 | ||

196 | And we were serious when we said that thing about how the bounds of | |

197 | the playfield are computed. | |

198 | ||

199 | | | |

200 | | v @ | |

201 | | #< 17 | |

202 | | | |

203 | = Result: 1 | |

204 | ||

205 | Arithmetic | |

206 | ---------- | |

207 | ||

208 | The `+` term evaluates whatever is to the north of it, then evaluates | |

209 | whatever is to the south of it, and evaluates to the sum of those | |

210 | two resulting values. | |

211 | ||

212 | | 5 | |

213 | | +@ | |

214 | | 7 | |

215 | = Result: 12 | |

216 | ||

217 | | 5<< | |

218 | | +<< | |

219 | | 7<< +<@ | |

220 | | 6< | |

221 | = Result: 18 | |

222 | ||

223 | The `*` term evaluates whatever is to the north of it, then evaluates | |

224 | whatever is to the south of it, and evaluates to the product of those | |

225 | two resulting values. | |

226 | ||

227 | | 5 | |

228 | | *@ | |

229 | | 7 | |

230 | = Result: 35 | |

231 | ||

232 | The `-` term evaluates whatever is to the north of it (and we call that | |

233 | /a/), then evaluates whatever is to the south of it (and we call that /b/). | |

234 | It evaluates to the difference, /a/ - /b/. | |

235 | ||

236 | | 7 | |

237 | | -@ | |

238 | | 5 | |

239 | = Result: 2 | |

240 | ||

241 | Subtraction resulting in a negative value. | |

242 | ||

243 | | 1 | |

244 | | -@ | |

245 | | 9 | |

246 | = Result: -8 | |

247 | ||

248 | The `/` term evaluates whatever is to the north of it (and we call that | |

249 | /a/), then evaluates whatever is to the south of it (and we call that /b/). | |

250 | It evaluates to the quotient of dividing /a/ by /b/. | |

251 | ||

252 | | 8 | |

253 | | /@ | |

254 | | 2 | |

255 | = Result: 4 | |

256 | ||

257 | Integer division rounds down. | |

258 | ||

259 | | 9 | |

260 | | /@ | |

261 | | 2 | |

262 | = Result: 4 | |

263 | ||

264 | Division by zero evaluates to whatever the cell on the other side | |

265 | of the `/` term evaluates to. | |

266 | ||

267 | | 9 | |

268 | | 7/@ | |

269 | | 0 | |

270 | = Result: 7 | |

271 | ||

272 | | v9#@ | |

273 | | >/7 | |

274 | | 0 | |

275 | = Result: 7 | |

276 | ||

277 | The `%` term evaluates whatever is to the north of it (and we call that | |

278 | /a/), then evaluates whatever is to the south of it (and we call that /b/). | |

279 | It evaluates to the remainder of dividing /a/ by /b/. This operation is | |

280 | called "modulo". | |

281 | ||

282 | | 8 | |

283 | | %@ | |

284 | | 3 | |

285 | = Result: 2 | |

286 | ||

287 | Modulo of a negative value has the sign of the dividend. | |

288 | ||

289 | | 7 | |

290 | | 0%@ | |

291 | | +< | |

292 | | 3 | |

293 | = Result: 1 | |

294 | ||

295 | | 7 | |

296 | | 0%@ | |

297 | | -< | |

298 | | 3 | |

299 | = Result: 1 | |

300 | ||

301 | Modulo by zero evaluates to whatever the cell on the other side | |

302 | evaluates to. | |

303 | ||

304 | | 9 | |

305 | | 7%@ | |

306 | | 0 | |

307 | = Result: 7 | |

308 | ||

309 | | v9#@ | |

310 | | >%7 | |

311 | | 0 | |

312 | = Result: 7 | |

313 | ||

314 | Decision Making | |

315 | --------------- | |

316 | ||

317 | 'Horizontal if', denoted `_`, checks what the cell on the other side | |

318 | of it evaluates to. If that value is nonzero, it evaluates to what | |

319 | the cell west of it evaluates to; otherwise, it evaluates to what the | |

320 | cell east of it evaluates to. In either case, at most two evaluations | |

321 | are made. | |

322 | ||

323 | | 0 | |

324 | | 5_9 | |

325 | | ^@ | |

326 | = Result: 9 | |

327 | ||

328 | | 7 | |

329 | | | |

330 | | 5 _ 9 | |

331 | | | |

332 | | ^@ | |

333 | = Result: 5 | |

334 | ||

335 | | v< | |

336 | | | |

337 | | 5 _ 9 | |

338 | | | |

339 | | 7^@ | |

340 | = Result: 5 | |

341 | ||

342 | 'Vertical if', denoted `|`, checks what the other side of it evaluates to. | |

343 | If that value is nonzero, it evaluates to what the cell north of it | |

344 | evaluates to; otherwise, it evaluates to what the cell south of it | |

345 | evaluates to. In either case, at most two evaluations are made. | |

346 | ||

347 | | 3 | |

348 | | 0|@ | |

349 | | 4 | |

350 | = Result: 4 | |

351 | ||

352 | | 3 | |

353 | | | |

354 | | 9 | @ | |

355 | | | |

356 | | 4 | |

357 | = Result: 3 | |

358 | ||

359 | | 3 | |

360 | | v @ | |

361 | | > | 9 | |

362 | | | |

363 | | 4 | |

364 | = Result: 3 | |

365 | ||

366 | These "if"s can be used to evaluate a cell for its side-effects only. | |

367 | In the following, the sum is evaluated, but the result is effectively | |

368 | thrown out, in preference to the zero. | |

369 | ||

370 | | 90 < | |

371 | | +|@ | |

372 | | 9> ^ | |

373 | = Result: 0 | |

374 | ||

375 | Like Befunge-93, `!` is logical negation: it evaluates to zero if the | |

376 | cell on the other side evaluates to non-zero, and to one if the cell on | |

377 | the other side evaluates to zero. | |

378 | ||

379 | | 0!@ | |

380 | = Result: 1 | |

381 | ||

382 | | > v | |

383 | | ^@ ! | |

384 | | 9 | |

385 | = Result: 0 | |

386 | ||

387 | We don't need greater than, because we can subtract one value | |

388 | from other, divide the result by itself (specifying a result of 0 | |

389 | if the division is by zero), then add one, and check if that is | |

390 | non-zero or not with a horizontal or vertical if. | |

391 | ||

392 | But because Befunge-93 has it, we have it too. The <code>`</code> term | |

393 | evaluates whatever is to the north of it (and we call that /a/), then | |

394 | evaluates whatever is to the south of it (and we call that /b/). It | |

395 | evaluates to 1 if /a/ is greater than /b/, 0 otherwise. | |

396 | ||

397 | | 8 | |

398 | | `@ | |

399 | | 7 | |

400 | = Result: 1 | |

401 | ||

402 | | 8 | |

403 | | `@ | |

404 | | 8 | |

405 | = Result: 0 | |

406 | ||

407 | | 8 | |

408 | | `@ | |

409 | | 9 | |

410 | = Result: 0 | |

411 | ||

412 | `?` picks one of the cardinal directions at random and evaluates | |

413 | to whatever the cell in that direction evaluates to. `?` should | |

414 | use a fair distribution of the four possible choices, and should | |

415 | be difficult to predict. We will not present this as a testable | |

416 | example program, because the Falderal test framework doesn't | |

417 | provide a way to test that, currently. (And it's not implemented | |

418 | yet, but never mind that.) Instead, here is a plain example. | |

419 | ||

420 | 1 | |

421 | 2?3#@ | |

422 | 4 | |

423 | ||

424 | The above program should evaluate to 1 25% of the time, 2 25% of | |

425 | the time, 3 25% of the time, and 4 the rest of the time. | |

426 | ||

427 | Introspection and Self-Modification | |

428 | ----------------------------------- | |

429 | ||

430 | Just like Befunge-93, program introspection and self-modification | |

431 | are fully supported. | |

432 | ||

433 | The `g` term evaluates to the north to get an x coordinate, then | |

434 | to the south to get a y coordinate, and evaluates to the ASCII value | |

435 | of the symbol that's found in that cell in the playfield. The origin | |

436 | (coordinates (0,0)) of the playfield is the upper-left corner of that | |

437 | bounding box I mentioned above, and x values increase to the right, | |

438 | and y values to the south. | |

439 | ||

440 | | A0 | |

441 | | g@ | |

442 | | 0 | |

443 | = Result: 65 | |

444 | ||

445 | The `p` term evaluates to the north to get an x coordinate, then | |

446 | to the south to get a y coordinate. It then evaluates what is on | |

447 | the other side of it to get a value. It then alters the playfield | |

448 | in effect, by placing that value at that (x,y) coordinate. The | |

449 | coordinate system is the same as that used by `g`. The `p` term | |

450 | always itself evaluates to zero. | |

451 | ||

452 | | 0 | |

453 | | 5p @ | |

454 | | 0 | |

455 | = Result: 0 | |

456 | ||

457 | | 0 | |

458 | | 5 p < | |

459 | | 0 +@ | |

460 | | g < | |

461 | | 0 | |

462 | = Result: 5 | |

463 | ||

464 | | 0 | |

465 | | > p 5 | |

466 | | +@ | |

467 | | 0 | |

468 | | > g | |

469 | | 0 | |

470 | = Result: 5 | |

471 | ||

472 | Writing a space over an existing cell deletes that cell, and affects | |

473 | the calculation of the bounds of the playfield. | |

474 | ||

475 | | 85 5 | |

476 | | *p< | |

477 | | 40+@ | |

478 | | > + | |

479 | | 9 | |

480 | | 9 | |

481 | = Result: 18 | |

482 | ||

483 | | 5 | |

484 | | 85 # | |

485 | | *p< | |

486 | | 40+@ | |

487 | | > ^ | |

488 | | 6 | |

489 | | 9 | |

490 | = Result: 6 | |

491 | ||

492 | Writing outside the bounds of the playfield expands those bounds. | |

493 | Since only cardinal directions are allowed in evaluation, the space | |

494 | is still topologically a torus; no Lahey-space-like construction | |

495 | is necessary. | |

496 | ||

497 | | 99> v | |

498 | | 7p*^@ >># | |

499 | | 16 >+ | |

500 | | <^ | |

501 | = Result: 7 | |

502 | ||

503 | Every cell in the playfield can hold a signed, unbounded integer. | |

504 | ||

505 | | c 00 | |

506 | | -p < | |

507 | | 90 +@ | |

508 | | g < | |

509 | | 0 | |

510 | = Result: -9 | |

511 | ||

512 | | 9 | |

513 | | *< 0 | |

514 | | 9* p < | |

515 | | *< 0 +@ | |

516 | | 9 g < | |

517 | | 0 | |

518 | = Result: 6561 | |

519 | ||

520 | (One consequence of the above two facts is that there are at least | |

521 | two tactics available for demonstrating that Flobnar is Turing- | |

522 | complete; the playfield could be used as a tape in the simulation | |

523 | of a Turing machine, or two cells could be used as registers in | |

524 | the simulation of a Minsky machine.) | |

525 | ||

526 | Evaluating a cell whose value is not the ASCII value of any of the | |

527 | characters which denote terms defined in this document is a | |

528 | runtime error, which results in the immediate termination of the | |

529 | program, without producing a result value. | |

530 | ||

531 | 9 | |

532 | *<5 | |

533 | 9*p< | |

534 | *<0+@7 | |

535 | 9 > v | |

536 | ||

537 | The above program will result in a runtime error. | |

538 | ||

539 | Functions | |

540 | --------- | |

541 | ||

542 | There's no real equivalent to Befunge-93's `:`, because there's no | |

543 | need. Common subexpressions can be shared geometrically. | |

544 | ||

545 | | v< | |

546 | | 5+@ | |

547 | | ^< | |

548 | = Result: 10 | |

549 | ||

550 | Likewise, there are no equivalents for `\` and `$`. Therefore, these | |

551 | symbols have different meanings in Flobnar. | |

552 | ||

553 | Originally, my idea for Flobnar included function values (lambda | |

554 | functions.) But eventually these struck me as un-Befunge-like. | |

555 | A function is just some code you want to be able to evaluate more | |

556 | than once without repeating verbatim. And in the context of Befunge, | |

557 | a function is just a part of the playfield. It's already possible | |

558 | to execute the same part of the playfield from different points in | |

559 | your program, using arrows; and in Flobnar this is even easier, | |

560 | since evaluation of a part of th playfield "remembers" where it was | |

561 | "evaluated from". | |

562 | ||

563 | What's really useful in a function is that it can take an argument. | |

564 | So I retained the idea of having arguments available -- a call stack. | |

565 | Surprisingly, it turned out to be similar to Befunge-93's stack, so I | |

566 | consider that a bonus. | |

567 | ||

568 | The `\` term takes what to the south of it evaluates to, and uses | |

569 | that as the argument as it "applies" the "one-argument" "function" on | |

570 | the other side of it. The `:` term evaluates to the current argument. | |

571 | ||

572 | | 5\@ | |

573 | | 0 | |

574 | = Result: 5 | |

575 | ||

576 | | : | |

577 | | +\@ | |

578 | | 54 | |

579 | = Result: 9 | |

580 | ||

581 | | v 1# \ @ | |

582 | | > + | |

583 | | | |

584 | | : 7 | |

585 | = Result: 8 | |

586 | ||

587 | | > v : | |

588 | | ^@>\* | |

589 | | 7: | |

590 | = Result: 49 | |

591 | ||

592 | If no function is being applied, `:` evaluates to zero. | |

593 | ||

594 | | :@ | |

595 | = Result: 0 | |

596 | ||

597 | A function can call another function. The outer function retains its | |

598 | argument after the inner function returns. | |

599 | ||

600 | | 1 | |

601 | | +\< | |

602 | | :4+\@ | |

603 | | :7 | |

604 | = Result: 12 | |

605 | ||

606 | Hellooooo, factorial! | |

607 | ||

608 | | > v | |

609 | | ^\ < | |

610 | | | |

611 | | :v v \<@ | |

612 | | -< : 6 | |

613 | | 1 : > * | |

614 | | -| < | |

615 | | 11 | |

616 | = Result: 720 | |

617 | ||

618 | The `$` term removes the top value from the call stack and "calls" the | |

619 | "function" on the other side with this reduced call stack. This, in | |

620 | effect, lets you write functions which take multiple arguments. | |

621 | ||

622 | | : | |

623 | | +\<<\@ | |

624 | | :7 9 | |

625 | = Result: 14 | |

626 | ||

627 | | : | |

628 | | $ | |

629 | | +\<<\@ | |

630 | | :7 9 | |

631 | = Result: 16 | |

632 | ||

633 | Input and Output | |

634 | ---------------- | |

635 | ||

636 | Flobnar supports input and output of ASCII characters, although | |

637 | because the Falderal test framework doesn't handle tests with | |

638 | input very well (and because I would have to refactor my beautiful | |

639 | implementation in a major way, either threading an IO monad | |

640 | through all the evaluation functions, or converting those | |

641 | functions to continuation-passing style), they are only briefly | |

642 | covered here, with only plain examples. My apologies if they are | |

643 | not very well defined; a future version of the language and the | |

644 | test suite may attempt to rectify that. | |

645 | ||

646 | The `,` term evaluates what is on the other side of it and | |

647 | outputs the character with that ASCII value to standard output. | |

648 | The `,` term itself evaluates to zero. So, the following | |

649 | example should output the two-character string 'Hi', and evaluate | |

650 | to a result of zero. | |

651 | ||

652 | 8 | |

653 | *,< 5 | |

654 | 9 +@>* | |

655 | >,*7 | |

656 | 3 | |

657 | ||

658 | Note that the convention of the result of each program being | |

659 | printed after "Result: ", in the tests here, is merely a convention. | |

660 | What the implementation does with the result of the main Flobnar | |

661 | expression is outside the domain of Flobnar proper. (Of course, | |

662 | it is extremely useful if it can make this value available to the | |

663 | outside world somehow, for example by outputting it after the | |

664 | string "Result: ".) | |

665 | ||

666 | In similar vein, attempting to output and integer outside the range | |

667 | of ASCII is, as of this writing, undefined. | |

668 | ||

669 | The `~` term reads a character from standard input and evaluates | |

670 | to the ASCII value of that character. So, the following program | |

671 | reads two characters, and evaluates to 1 if they are the same | |

672 | character, and 0 if they are not. | |

673 | ||

674 | ~ | |

675 | -!@ | |

676 | ~ | |

677 | ||

678 | Putting these two together, the following program should be the | |

679 | virtual equivalent of the Unix `cat` utility: | |

680 | ||

681 | ~,< | |

682 | +<@ | |

683 | >^ | |

684 | ||

685 | Other Things | |

686 | ------------ | |

687 | ||

688 | The terms denoted by all characters not mentioned in the above | |

689 | sections are undefined. For maximum compatibility with future | |

690 | versions of Flobnar, they should not appear in a Flobnar program. | |

691 | ||

692 | Specifically, I have a vague idea that extensions to Flobnar | |

693 | may be indicated by the presence of a certain characters or | |

694 | combination of characters immediately and non-wrappingly to | |

695 | the east of the `@` term. So, best to leave that cell blank or | |

696 | make it an arrow. | |

697 | ||

698 | As you've probably noticed, I've referred to the character set | |

699 | as ASCII in this entire document. I actually mean "printable | |

700 | ASCII" -- control characters and whitespace (aside from space | |

701 | and linefeed) are not defined, and (except for specific cases | |

702 | addressed in this document) an implementation is not expected | |

703 | to load them into the playfield. If at some point Flobnar is | |

704 | ever extended into the realm of Unicode, source files will be | |

705 | expected to be encoded in UTF-8. | |

706 | ||

707 | To be really true to Befunge-93, Flobnar should support `.` for | |

708 | outputting integers formatted in conventional decimal notation, | |

709 | and `&` for inputting integers in that format too. They may | |

710 | appear in a future version of the language. On the other hand, | |

711 | they may not. I can't see the future. | |

712 | ||

713 | After all that, the only thing from Befunge-93 that's missing a | |

714 | counterpart in Flobnar is stringmode. I originally added it to | |

715 | Flobnar, having each string evaluate to a string value, but that | |

716 | complicated evaluation rules by adding a new type that would have | |

717 | to be handled everywhere. I afterwards considered making it more | |

718 | like ':', pushing the ASCII value of each character onto the call | |

719 | stack, but decided that was a little awkward too. So, for | |

720 | simplicity, I just left it out of this version. | |

721 | ||

722 | That's All | |

723 | ---------- | |

724 | ||

725 | Happy bar-hopping! | |

726 | Chris Pressey | |

727 | Evanston, Illinois | |

728 | October 28, 2011 |

0 | -- encoding: UTF-8 | |

1 | ||

2 | -- | |

3 | -- Copyright (c)2011 Chris Pressey, Cat's Eye Technologies. | |

4 | -- All rights reserved. | |

5 | -- | |

6 | -- Redistribution and use in source and binary forms, with or without | |

7 | -- modification, are permitted provided that the following conditions | |

8 | -- are met: | |

9 | -- | |

10 | -- 1. Redistributions of source code must retain the above copyright | |

11 | -- notices, this list of conditions and the following disclaimer. | |

12 | -- 2. Redistributions in binary form must reproduce the above copyright | |

13 | -- notices, this list of conditions, and the following disclaimer in | |

14 | -- the documentation and/or other materials provided with the | |

15 | -- distribution. | |

16 | -- 3. Neither the names of the copyright holders nor the names of their | |

17 | -- contributors may be used to endorse or promote products derived | |

18 | -- from this software without specific prior written permission. | |

19 | -- | |

20 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |

21 | -- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |

22 | -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |

23 | -- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |

24 | -- COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |

25 | -- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |

26 | -- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |

27 | -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |

28 | -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |

29 | -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |

30 | -- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |

31 | -- POSSIBILITY OF SUCH DAMAGE. | |

32 | -- | |

33 | ||

34 | module Flobnar where | |

35 | ||

36 | import qualified Data.Map as Map | |

37 | import qualified Char as Char | |

38 | ||

39 | data Value = IntVal Integer | |

40 | deriving (Show, Ord, Eq) | |

41 | ||

42 | -- ======================================= -- | |

43 | -- Playfield data definition and functions -- | |

44 | -- ======================================= -- | |

45 | ||

46 | type Playfield = Map.Map (Integer,Integer) Integer | |

47 | ||

48 | emptyPlayfield :: Playfield | |

49 | emptyPlayfield = Map.empty | |

50 | ||

51 | get :: Playfield -> Integer -> Integer -> Integer | |

52 | get pf x y = Map.findWithDefault 32 (x, y) pf | |

53 | ||

54 | put :: Playfield -> Integer -> Integer -> Integer -> Playfield | |

55 | put pf x y value = | |

56 | case value of | |

57 | 32 -> Map.delete (x, y) pf | |

58 | _ -> Map.insert (x, y) value pf | |

59 | ||

60 | putc :: Playfield -> Integer -> Integer -> Char -> Playfield | |

61 | putc pf x y char = put pf x y (toInteger $ Char.ord char) | |

62 | ||

63 | loadLine pf x y [] = pf | |

64 | loadLine pf x y (char:chars) = | |

65 | loadLine (putc pf x y char) (x+1) y chars | |

66 | ||

67 | loadLines pf x y [] = pf | |

68 | loadLines pf x y (line:lines) = | |

69 | loadLines (loadLine pf x y line) x (y+1) lines | |

70 | ||

71 | load lines = loadLines emptyPlayfield 0 0 lines | |

72 | ||

73 | locate pf value = | |

74 | let | |

75 | f accum key val = | |

76 | if val == value then | |

77 | ((key:accum), val) | |

78 | else | |

79 | (accum, val) | |

80 | in | |

81 | fst $ Map.mapAccumWithKey f [] pf | |

82 | ||

83 | extents pf = | |

84 | let | |

85 | f (lowX, lowY, highX, highY) (x, y) val = | |

86 | let | |

87 | lowX' = if x < lowX then x else lowX | |

88 | lowY' = if y < lowY then y else lowY | |

89 | highX' = if x > highX then x else highX | |

90 | highY' = if y > highY then y else highY | |

91 | in | |

92 | ((lowX', lowY', highX', highY'), val) | |

93 | in | |

94 | fst $ Map.mapAccumWithKey f (1000, 1000, (-1000), (-1000)) pf | |

95 | ||

96 | -- ================== -- | |

97 | -- Flobnar evaluation -- | |

98 | -- ================== -- | |

99 | ||

100 | -- | |

101 | -- Evaluation is implemented as a set of mutually recursive functions. | |

102 | -- Evaluation functions return a pair of (result value, new playfield). | |

103 | -- All terms except p leave the playfield unchanged. | |

104 | -- | |

105 | -- env is a list of values; each value is the argument that was passed | |

106 | -- to a function that was called to get here. | |

107 | -- | |

108 | -- dx and dy are the delta that the expression is being evaluated from: | |

109 | -- | |

110 | -- dx=0, dy=1: being evaluated from the north (toward the south) | |

111 | -- dx=0, dy=-1: being evaluated from the south (toward the north) | |

112 | -- dx=1, dy=0: being evaluated from the west (toward the east) | |

113 | -- dx=-1, dy=0: being evaluated from the east (toward the west) | |

114 | -- | |

115 | -- Terms should call one of these 6 functions to evaluate another | |

116 | -- location in the playfield, as these functions handle wrapping. | |

117 | -- Don't call eval directly unless you know (x, y) is in the playfield. | |

118 | -- | |

119 | ||

120 | evalEast env pf x y = evalDelta env pf 1 0 x y | |

121 | evalWest env pf x y = evalDelta env pf (-1) 0 x y | |

122 | evalNorth env pf x y = evalDelta env pf 0 (-1) x y | |

123 | evalSouth env pf x y = evalDelta env pf 0 1 x y | |

124 | evalDelta env pf dx dy x y = evalLeap env pf dx dy dx dy x y | |

125 | evalLeap env pf dx dy leapDx leapDy x y = | |

126 | let | |

127 | (nx, ny) = wrap pf (x+leapDx) (y+leapDy) | |

128 | in | |

129 | eval env pf dx dy nx ny | |

130 | ||

131 | wrap pf x y = | |

132 | let | |

133 | (lowX, lowY, highX, highY) = extents pf | |

134 | x' = if (x < lowX) then highX-(lowX-x)+1 else | |

135 | if (x > highX) then lowX+(x-highX)-1 else x | |

136 | y' = if (y < lowY) then highY-(lowY-y)+1 else | |

137 | if (y > highY) then lowY+(y-highY)-1 else y | |

138 | in | |

139 | (x', y') | |

140 | ||

141 | ||

142 | eval env pf dx dy x y = | |

143 | let | |

144 | term = Char.chr $ fromInteger $ get pf x y | |

145 | in | |

146 | evalThe term env pf dx dy x y | |

147 | ||

148 | -- | |

149 | -- Evaluation of individual terms. The meaning of each of these is | |

150 | -- explained in the documentation. | |

151 | -- | |

152 | ||

153 | evalThe :: Char -> [Value] -> Playfield -> Integer -> Integer -> Integer -> Integer -> (Value, Playfield) | |

154 | ||

155 | evalThe ':' (arg:env) pf dx dy x y = (arg, pf) | |

156 | evalThe ':' [] pf dx dy x y = (IntVal 0, pf) | |

157 | ||

158 | evalThe '$' (arg:env) pf dx dy x y = evalDelta env pf dx dy x y | |

159 | evalThe '$' [] pf dx dy x y = evalDelta [] pf dx dy x y | |

160 | ||

161 | evalThe '\\' env pf dx dy x y = | |

162 | let | |

163 | (arg, pf') = evalSouth env pf x y | |

164 | in | |

165 | evalDelta (arg:env) pf' dx dy x y | |

166 | ||

167 | evalThe '>' env pf dx dy x y = evalEast env pf x y | |

168 | evalThe '<' env pf dx dy x y = evalWest env pf x y | |

169 | evalThe 'v' env pf dx dy x y = evalSouth env pf x y | |

170 | evalThe '^' env pf dx dy x y = evalNorth env pf x y | |

171 | ||

172 | evalThe '_' env pf dx dy x y = | |

173 | case evalDelta env pf dx dy x y of | |

174 | (IntVal 0, pf') -> evalEast env pf' x y | |

175 | (_, pf') -> evalWest env pf' x y | |

176 | ||

177 | evalThe '|' env pf dx dy x y = | |

178 | case evalDelta env pf dx dy x y of | |

179 | (IntVal 0, pf') -> evalSouth env pf' x y | |

180 | (_, pf') -> evalNorth env pf' x y | |

181 | ||

182 | evalThe '@' env pf dx dy x y = evalWest env pf x y | |

183 | ||

184 | evalThe '!' env pf dx dy x y = | |

185 | case evalDelta env pf dx dy x y of | |

186 | (IntVal 0, pf') -> (IntVal 1, pf') | |

187 | (_, pf') -> (IntVal 0, pf') | |

188 | ||

189 | evalThe ' ' env pf dx dy x y = | |

190 | evalDelta env pf dx dy x y | |

191 | ||

192 | evalThe '#' env pf dx dy x y = | |

193 | evalLeap env pf dx dy (dx*2) (dy*2) x y | |

194 | ||

195 | evalThe digit env pf dx dy x y | |

196 | | Char.isDigit digit = (IntVal $ toInteger $ Char.digitToInt digit, pf) | |

197 | ||

198 | evalThe oper env pf dx dy x y = | |

199 | let | |

200 | (IntVal north, pf') = evalNorth env pf x y | |

201 | (IntVal south, pf'') = evalSouth env pf' x y | |

202 | in | |

203 | case oper of | |

204 | '+' -> (IntVal (north + south), pf'') | |

205 | '*' -> (IntVal (north * south), pf'') | |

206 | '-' -> (IntVal (north - south), pf'') | |

207 | '/' -> case south of | |

208 | 0 -> evalDelta env pf'' dx dy x y | |

209 | _ -> (IntVal (north `div` south), pf'') | |

210 | '%' -> case south of | |

211 | 0 -> evalDelta env pf'' dx dy x y | |

212 | _ -> (IntVal (north `rem` south), pf'') | |

213 | '`' -> case north > south of | |

214 | True -> (IntVal 1, pf'') | |

215 | False -> (IntVal 0, pf'') | |

216 | 'g' -> (IntVal $ get pf'' north south, pf'') | |

217 | 'p' -> let | |

218 | (IntVal value, pf''') = evalDelta env pf'' dx dy x y | |

219 | pf'''' = put pf''' north south value | |

220 | in | |

221 | (IntVal 0, pf'''') | |

222 | _ -> | |

223 | error "undefined term" | |

224 | ||

225 | -- | |

226 | -- Main entry points for executing Flobnar programs. | |

227 | -- | |

228 | ||

229 | run program = | |

230 | let | |

231 | pf = load (lines program) | |

232 | in | |

233 | case locate pf $ toInteger $ Char.ord '@' of | |

234 | [(x, y)] -> | |

235 | let | |

236 | (result, pf') = eval [] pf 0 0 x y | |

237 | in | |

238 | result | |

239 | _ -> | |

240 | error "Program does not contain exactly one @" | |

241 | ||

242 | showRun program = | |

243 | case run program of | |

244 | IntVal x -> "Result: " ++ (show x) |