├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | jobs: 7 | allow_failures: 8 | - rust: nightly 9 | fast_finish: true 10 | cache: cargo 11 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "fortraith" 5 | version = "0.1.3" 6 | dependencies = [ 7 | "trait_eval", 8 | ] 9 | 10 | [[package]] 11 | name = "trait_eval" 12 | version = "0.1.3" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | checksum = "91476d781cbce5a1a83e66c5c7696c256bd929472b3e68aa959decbd5dd1b649" 15 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fortraith" 3 | version = "0.1.3" 4 | authors = ["Szymon Mikulicz "] 5 | edition = "2018" 6 | license = "MIT" 7 | keywords = ["const", "traits", "compile-time", "evaluator"] 8 | categories = ["satire"] 9 | description = "Compile-time compiler that compiles Forth to compile-time trait expressions." 10 | homepage = "https://github.com/Ashymad/fortraith" 11 | repository = "https://github.com/Ashymad/fortraith" 12 | readme = "README.md" 13 | 14 | [dependencies] 15 | trait_eval = "0" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Szymon Mikulicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `fortraith` 2 | [![Docs.rs](https://docs.rs/fortraith/badge.svg)](https://docs.rs/fortraith) 3 | [![Crates.io](https://img.shields.io/crates/v/fortraith.svg?style=plastic)](https://crates.io/crates/fortraith) 4 | [![Build Status](https://travis-ci.com/Ashymad/fortraith.svg?branch=master)](https://travis-ci.com/Ashymad/fortraith) 5 | 6 | Compile-time compiler that compiles Forth to compile-time trait expressions. 7 | 8 | ## What? 9 | Rust's trait system is Turing complete. This crate uses the principles from 10 | [trait-eval](https://github.com/doctorn/trait-eval/) to implement necessary 11 | traits for forth evaluation and provides a `forth!` macro that transpiles 12 | forth's syntax to trait expressions. 13 | 14 | ## Show me! 15 | Here's a simple factorial implementation, the only non-standard word here is 16 | `pred` which is a decrement operator, equivalent to `1 -`: 17 | ```rust 18 | forth!( 19 | : factorial (n -- n) 1 swap fact0 ; 20 | : fact0 (n n -- n) dup 1 = if drop else dup rot * swap pred fact0 then ; 21 | 5 factorial . 22 | ); 23 | ``` 24 | This prints `120`. As you can see not only can you define functions easily, but even conditional recursion is possible! 25 | Now check out how it looks compiled to trait expressions (courtesy of `cargo expand`): 26 | ```rust 27 | pub trait factorial { 28 | type Result; 29 | } 30 | impl factorial for Node 31 | where 32 | Self: one, 33 | ::Result: swap, 34 | <::Result as swap>::Result: fact0, 35 | { 36 | type Result = <<::Result as swap>::Result as fact0>::Result; 37 | } 38 | pub trait fact0 { 39 | type Result; 40 | } 41 | impl fact0 for Node 42 | where 43 | Self: dup, 44 | ::Result: one, 45 | <::Result as one>::Result: eq, 46 | <<::Result as one>::Result as eq>::Result: iff, 47 | <<<::Result as one>::Result as eq>::Result as iff>::Result: drop, 48 | <<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result: elsef, 49 | <<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result: dup, 50 | <<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result: rot, 51 | <<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result: mult, 52 | <<<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result as mult>::Result: swap, 53 | <<<<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result as mult>::Result as swap>::Result: pred, 54 | <<<<<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result as mult>::Result as swap>::Result as pred>::Result: fact0, 55 | <<<<<<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result as mult>::Result as swap>::Result as pred>::Result as fact0>::Result: then 56 | { 57 | type Result = <<<<<<<<<<<<::Result as one>::Result as eq>::Result as iff>::Result as drop>::Result as elsef>::Result as dup>::Result as rot>::Result as mult>::Result as swap>::Result as pred>::Result as fact0>::Result as then>::Result; 58 | } 59 | println!("{}", <<::Result as factorial>::Result as top>::Result::eval()); 60 | ``` 61 | Yeah, writing that manually would be no fun. 62 | 63 | ## What can I do with it? 64 | Quite a bit is actually supported as you can see above. Every operation from 65 | `trait-eval` is re-exported to work on the stack (except `if` which is done 66 | differently), and a few additional stack operations are provided. See [docs](https://docs.rs/fortraith) 67 | for the details. 68 | 69 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Compile-Time Compiler That Compiles Forth to Trait Expressions 2 | //! 3 | //! "We all know Rust's trait system is Turing complete, so tell me, why aren't we exploiting 4 | //! this???" - [Nathan Corbyn](https://github.com/doctorn/trait-eval) 5 | //! 6 | //!``` 7 | //! #![recursion_limit = "256"] 8 | //! #[macro_use] extern crate fortraith; 9 | //! use fortraith::*; 10 | //! 11 | //! forth!( 12 | //! : factorial (n -- n) 1 swap fact0 ; 13 | //! : fact0 (n n -- n) dup 1 = if drop else dup rot * swap pred fact0 then ; 14 | //! 5 factorial 15 | //! return type Out as top 16 | //! ); 17 | //! assert_eq!(Out::eval(), 120); 18 | //!``` 19 | //! This crate allows the user to exploit traits as much as wanted. It contains around 10% black 20 | //! trait magic, around 40% of the darkest kind of evil macro magic and around 50% of good quality 21 | //! docs (you are here!). Everything is tested and ready for production (a joke). 22 | //! 23 | //! Although you might not want to really use it in production it serves to show how powerful 24 | //! Rust's trait system and `macro_rules!` really are. 25 | //! 26 | //! If you are new to forth, it is a simple stack-based language. Every operation is done on the 27 | //! stack and grabs and pushes values into it. For example `2 2 +` would push `2` to the top of the 28 | //! stack 2 times, take and add them together and push the result back to the stack (So the stack 29 | //! would have only `4` in it if it was empty before pushing the first `2`). Its simplicity makes 30 | //! it a usual target for recreational implementation. 31 | //! 32 | //! See documentation for traits and the macro to see many examples and learn how to use fortraith, 33 | //! and abuse the Rust's trait system! 34 | //! 35 | //! "Ok, ok, all that's fine, but where is my FizzBuzz implementation?" you might ask. Fear not, as 36 | //! tradition dictates [FizzBuzz is implemented in fortraith as well](trait.iff.html). 37 | 38 | #![allow(non_camel_case_types)] 39 | use std::marker::PhantomData; 40 | use trait_eval::*; 41 | pub use trait_eval::Eval; 42 | 43 | #[doc(hidden)] 44 | pub struct Empty {} 45 | 46 | #[doc(hidden)] 47 | pub struct Node { 48 | _val: PhantomData, 49 | _next: PhantomData, 50 | } 51 | 52 | #[doc(hidden)] 53 | pub struct Stop { 54 | _next: PhantomData, 55 | } 56 | 57 | macro_rules! pub_trait { 58 | ($($(#[$meta:meta])* $name:ident),*) => { 59 | $( 60 | $(#[$meta])* 61 | pub trait $name { 62 | type Result; 63 | } 64 | )* 65 | } 66 | } 67 | 68 | pub_trait!( 69 | /// Remove the top element 70 | /// # Examples 71 | /// ``` 72 | /// # #[macro_use] extern crate fortraith; 73 | /// # use fortraith::*; 74 | /// forth!( 75 | /// 1 2 drop 76 | /// return type Out as top 77 | /// ); 78 | /// assert_eq!(Out::eval(), 1); 79 | /// ``` 80 | drop, 81 | 82 | /// Duplicate the top element 83 | /// # Examples 84 | /// ``` 85 | /// # #[macro_use] extern crate fortraith; 86 | /// # use fortraith::*; 87 | /// forth!( 88 | /// 2 dup + 89 | /// return type Out as top 90 | /// ); 91 | /// assert_eq!(Out::eval(), 4); 92 | /// ``` 93 | dup, 94 | 95 | /// Swap two top elements 96 | /// # Examples 97 | /// ``` 98 | /// # #[macro_use] extern crate fortraith; 99 | /// # use fortraith::*; 100 | /// forth!( 101 | /// 1 2 swap - 102 | /// return type Out as top 103 | /// ); 104 | /// assert_eq!(Out::eval(), 1); 105 | /// ``` 106 | swap, 107 | 108 | /// Rotate three top elements 109 | /// # Examples 110 | /// Rotates 1 2 3 -> 2 3 1 -> 3 1 2 111 | /// ``` 112 | /// # #[macro_use] extern crate fortraith; 113 | /// # use fortraith::*; 114 | /// forth!( 115 | /// 1 2 3 rot rot 116 | /// return type Out as top 117 | /// ); 118 | /// assert_eq!(Out::eval(), 2); 119 | /// ``` 120 | rot, 121 | 122 | /// Get the top element 123 | /// # Examples 124 | /// WARNING! This effectively discards the stack, so it should only be used with the `return` 125 | /// statement 126 | /// ``` 127 | /// # #[macro_use] extern crate fortraith; 128 | /// # use fortraith::*; 129 | /// forth!( 130 | /// 10 131 | /// return type Out1 as top 132 | /// 1 + top 133 | /// return type Out2 134 | /// ); 135 | /// type Out3 = forth!(9 top return); 136 | /// assert_eq!(Out1::eval(), 10); 137 | /// assert_eq!(Out2::eval(), 11); 138 | /// assert_eq!(Out3::eval(), 9); 139 | /// ``` 140 | top, 141 | 142 | /// ( if / else / then ) conditional expression 143 | /// 144 | /// ifs can be nested and can be used both inside and outside of a function. `else` clause is 145 | /// optional 146 | /// # Examples 147 | /// Return 9 if 10 is less than 1, else return 9 148 | /// ``` 149 | /// # #[macro_use] extern crate fortraith; 150 | /// # use fortraith::*; 151 | /// forth!( 152 | /// 10 1 < if 5 else 9 then 153 | /// return type Out as top 154 | /// ); 155 | /// assert_eq!(Out::eval(), 9); 156 | /// ``` 157 | /// FizzBuzz (of course), there are no strings or chars in fortraith so Fizz = true, Buzz = 158 | /// false and FizzBuzz = 0 159 | /// ``` 160 | /// # #![recursion_limit="256"] 161 | /// # #[macro_use] extern crate fortraith; 162 | /// # use fortraith::*; 163 | /// forth!( 164 | /// : FizzBuzz 165 | /// dup 3 % 0 = if 166 | /// 5 % 0 = if 167 | /// 0 (FizzBuzz) 168 | /// else 169 | /// true (Fizz) 170 | /// then 171 | /// else 172 | /// dup 5 % 0 = if 173 | /// drop false (Buzz) 174 | /// then 175 | /// then ; 176 | /// 1 FizzBuzz return type Out1 as top 177 | /// 2 FizzBuzz return type Out2 as top 178 | /// 3 FizzBuzz return type Out3 as top 179 | /// 4 FizzBuzz return type Out4 as top 180 | /// 5 FizzBuzz return type Out5 as top 181 | /// 10 5 + FizzBuzz return type Out15 as top 182 | /// ); 183 | /// assert_eq!(Out1::eval(), 1); 184 | /// assert_eq!(Out2::eval(), 2); 185 | /// assert_eq!(Out3::eval(), true); 186 | /// assert_eq!(Out4::eval(), 4); 187 | /// assert_eq!(Out5::eval(), false); 188 | /// assert_eq!(Out15::eval(), 0); 189 | /// ``` 190 | iff, 191 | 192 | #[doc(hidden)] 193 | elsef, 194 | 195 | #[doc(hidden)] 196 | then, 197 | 198 | /// Apply logical not to the top element 199 | /// # Examples 200 | /// ``` 201 | /// # #[macro_use] extern crate fortraith; 202 | /// # use fortraith::*; 203 | /// forth!( 204 | /// true not 205 | /// return type Out as top 206 | /// ); 207 | /// assert_eq!(Out::eval(), false); 208 | /// ``` 209 | not, 210 | 211 | /// Decrement the top element 212 | /// # Examples 213 | /// ``` 214 | /// # #[macro_use] extern crate fortraith; 215 | /// # use fortraith::*; 216 | /// forth!( 217 | /// 8 pred pred 218 | /// return type Out as top 219 | /// ); 220 | /// assert_eq!(Out::eval(), 6); 221 | /// ``` 222 | pred, 223 | 224 | /// Index the fibonacci sequence with the top element 225 | /// # Examples 226 | /// ``` 227 | /// # #[macro_use] extern crate fortraith; 228 | /// # use fortraith::*; 229 | /// forth!( 230 | /// 8 fib 231 | /// return type Out as top 232 | /// ); 233 | /// assert_eq!(Out::eval(), 21); 234 | /// ``` 235 | fib, 236 | 237 | /// Calculate the factorial of the top element 238 | /// 239 | /// Yeah you don't have to write the factorial word by yourself, it's builtin thanks to 240 | /// trait_eval! 241 | /// # Examples 242 | /// ``` 243 | /// # #[macro_use] extern crate fortraith; 244 | /// # use fortraith::*; 245 | /// forth!( 246 | /// 4 fact 247 | /// return type Out as top 248 | /// ); 249 | /// assert_eq!(Out::eval(), 24); 250 | /// ``` 251 | fact, 252 | 253 | /// ( + ) Add two top elements together 254 | /// # Examples 255 | /// ``` 256 | /// # #[macro_use] extern crate fortraith; 257 | /// # use fortraith::*; 258 | /// forth!( 259 | /// 9 3 2 + + 260 | /// return type Out as top 261 | /// ); 262 | /// assert_eq!(Out::eval(), 14); 263 | /// ``` 264 | plus, 265 | 266 | /// ( - ) Subtract the top element from the second top element 267 | /// # Examples 268 | /// ``` 269 | /// # #[macro_use] extern crate fortraith; 270 | /// # use fortraith::*; 271 | /// forth!( 272 | /// 7 5 - 273 | /// return type Out as top 274 | /// ); 275 | /// assert_eq!(Out::eval(), 2); 276 | /// ``` 277 | minus, 278 | 279 | /// ( % ) Calculate the rest from dividing the second top element by the top element 280 | /// # Examples 281 | /// ``` 282 | /// # #[macro_use] extern crate fortraith; 283 | /// # use fortraith::*; 284 | /// forth!( 285 | /// 7 4 % 286 | /// return type Out as top 287 | /// ); 288 | /// assert_eq!(Out::eval(), 3); 289 | /// ``` 290 | modulo, 291 | 292 | /// ( * ) Multiply two top elements 293 | /// # Examples 294 | /// ``` 295 | /// # #[macro_use] extern crate fortraith; 296 | /// # use fortraith::*; 297 | /// forth!( 298 | /// 7 4 * 299 | /// return type Out as top 300 | /// ); 301 | /// assert_eq!(Out::eval(), 28); 302 | /// ``` 303 | mult, 304 | 305 | /// ( = ) Check if two top elements are equal 306 | /// # Examples 307 | /// ``` 308 | /// # #[macro_use] extern crate fortraith; 309 | /// # use fortraith::*; 310 | /// forth!( 311 | /// 1 2 + 3 = 312 | /// return type Out as top 313 | /// ); 314 | /// assert_eq!(Out::eval(), true); 315 | /// ``` 316 | eq, 317 | 318 | /// ( < ) Check if the second top element is less than the top elements 319 | /// # Examples 320 | /// ``` 321 | /// # #[macro_use] extern crate fortraith; 322 | /// # use fortraith::*; 323 | /// forth!( 324 | /// 10 3 < 325 | /// return type Out as top 326 | /// ); 327 | /// assert_eq!(Out::eval(), false); 328 | /// ``` 329 | less, 330 | 331 | /// Logical and two top elements 332 | /// # Examples 333 | /// ``` 334 | /// # #[macro_use] extern crate fortraith; 335 | /// # use fortraith::*; 336 | /// forth!( 337 | /// true false and 338 | /// return type Out as top 339 | /// ); 340 | /// assert_eq!(Out::eval(), false); 341 | /// ``` 342 | and, 343 | 344 | /// Logical or two top elements 345 | /// # Examples 346 | /// ``` 347 | /// # #[macro_use] extern crate fortraith; 348 | /// # use fortraith::*; 349 | /// forth!( 350 | /// true false or 351 | /// return type Out as top 352 | /// ); 353 | /// assert_eq!(Out::eval(), true); 354 | /// ``` 355 | or, 356 | 357 | /// ( 0 ) Constant number 358 | zero, 359 | /// ( 1 ) Constant number 360 | one, 361 | /// ( 2 ) Constant number 362 | two, 363 | /// ( 3 ) Constant number 364 | three, 365 | /// ( 4 ) Constant number 366 | four, 367 | /// ( 5 ) Constant number 368 | five, 369 | /// ( 6 ) Constant number 370 | six, 371 | /// ( 7 ) Constant number 372 | seven, 373 | /// ( 8 ) Constant number 374 | eight, 375 | /// ( 9 ) Constant number 376 | nine, 377 | /// ( 10 ) Constant number 378 | ten, 379 | /// ( true ) Constant boolean 380 | truef, 381 | /// ( false ) Constant boolean 382 | falsef 383 | ); 384 | 385 | macro_rules! stack_op { 386 | (1, $name:ident, $op:ident, $type:ident) => { 387 | impl $name for Node 388 | where 389 | V: $op + $type, 390 | { 391 | type Result = Node; 392 | } 393 | }; 394 | (2, $name:ident, $op:ident, $type:ident) => { 395 | impl $name for Node 396 | where 397 | N: drop + top, 398 | V: $type, 399 | ::Result: $type + $op, 400 | { 401 | type Result = Node<<::Result as $op>::Result, ::Result>; 402 | } 403 | }; 404 | } 405 | 406 | stack_op!(1, not, Not, Bool); 407 | stack_op!(1, pred, Pred, Nat); 408 | stack_op!(1, fib, Fib, Nat); 409 | stack_op!(1, fact, Fact, Nat); 410 | 411 | stack_op!(2, plus, Plus, Nat); 412 | stack_op!(2, minus, Minus, Nat); 413 | stack_op!(2, modulo, Mod, Nat); 414 | stack_op!(2, mult, Times, Nat); 415 | stack_op!(2, eq, Equals, Nat); 416 | stack_op!(2, less, LessThan, Nat); 417 | stack_op!(2, and, AndAlso, Bool); 418 | stack_op!(2, or, OrElse, Bool); 419 | 420 | macro_rules! constant { 421 | ($name:ident, $con:ty) => { 422 | impl $name for Node { 423 | type Result = Node<$con, Self>; 424 | } 425 | impl $name for Empty { 426 | type Result = Node<$con, Self>; 427 | } 428 | }; 429 | } 430 | 431 | constant!(zero, Zero); 432 | constant!(one, One); 433 | constant!(two, Two); 434 | constant!(three, Three); 435 | constant!(four, Four); 436 | constant!(five, Five); 437 | constant!(six, Six); 438 | constant!(seven, Seven); 439 | constant!(eight, Eight); 440 | constant!(nine, Nine); 441 | constant!(ten, Ten); 442 | constant!(truef, True); 443 | constant!(falsef, False); 444 | 445 | impl drop for Node { 446 | type Result = N; 447 | } 448 | 449 | impl dup for Node { 450 | type Result = Node; 451 | } 452 | 453 | impl swap for Node 454 | where 455 | N: top + drop, 456 | { 457 | type Result = Node<::Result, Node::Result>>; 458 | } 459 | 460 | impl rot for Node 461 | where 462 | N: top + drop, 463 | ::Result: top + drop, 464 | { 465 | type Result = Node< 466 | <::Result as top>::Result, 467 | Node::Result, <::Result as drop>::Result>>, 468 | >; 469 | } 470 | 471 | impl top for Node { 472 | type Result = V; 473 | } 474 | 475 | impl iff for Node { 476 | type Result = N; 477 | } 478 | impl iff for Node { 479 | type Result = Stop; 480 | } 481 | impl iff for Stop { 482 | type Result = Stop; 483 | } 484 | 485 | impl elsef for Node { 486 | type Result = Stop; 487 | } 488 | impl elsef for Stop> { 489 | type Result = Self; 490 | } 491 | impl elsef for Stop> { 492 | type Result = Node; 493 | } 494 | impl elsef for Stop { 495 | type Result = Empty; 496 | } 497 | 498 | impl then for Node { 499 | type Result = Self; 500 | } 501 | impl then for Empty { 502 | type Result = Self; 503 | } 504 | impl then for Stop { 505 | type Result = N; 506 | } 507 | 508 | macro_rules! impl_for_stop { 509 | ($($trait:ident),*) => { 510 | $( 511 | impl $trait for Stop { 512 | type Result = Self; 513 | } 514 | )* 515 | }; 516 | } 517 | 518 | impl_for_stop!( 519 | top, drop, dup, plus, minus, modulo, mult, eq, less, and, or, zero, one, two, three, four, 520 | five, six, seven, eight, nine, ten, truef, falsef, swap, rot, not, pred, fact, fib 521 | ); 522 | 523 | /// Compile forth to trait expressions 524 | /// 525 | /// Every trait from this crate serves as a word than can be used in the forth program. 526 | /// Macro substitutes common names (`+ - * % < = if else true false`, numbers from `1` to `10`) for 527 | /// corresponding traits to make it easier. Everything inside parentheses `( )` is treated as comments 528 | /// and ignored by the macro. 529 | /// 530 | /// Additionally the macro provides a few special expressions (note that these cannot be used inside 531 | /// a new word definition): 532 | /// - `.` which is equivalent to `drop` but it inserts a `println` statement 533 | /// with the dropped value for convenience. You could call this cheating, but there is no way to 534 | /// print types at compile time known to me. 535 | /// ``` 536 | /// # #[macro_use] extern crate fortraith; 537 | /// # use fortraith::*; 538 | /// forth!( 539 | /// 10 . 540 | /// ); 541 | /// // prints "10" 542 | /// ``` 543 | /// - `: $name $($cmds)* ;` which defines a new word (trait) named `$name` that executes commands 544 | /// given after the name 545 | /// ``` 546 | /// # #[macro_use] extern crate fortraith; 547 | /// # use fortraith::*; 548 | /// forth!( 549 | /// : booltonum if 0 else 1 then ; 550 | /// true booltonum 551 | /// false booltonum 552 | /// + 553 | /// return type Out as top 554 | /// ); 555 | /// assert_eq!(Out::eval(), 1); 556 | /// ``` 557 | /// - `return` which can be used in 3 different ways: 558 | /// - `return` at the end of the program returns the current stack (This can only be used if 559 | /// `.`, `:;`, or another `return` are not used in the program) 560 | /// - `return type $name` anywhere inside the program saves the stack to a type alias `$name` 561 | /// - `return type $name as $cmd` anywhere inside the program saves the stack after executing 562 | /// `$cmd` on the stack to type alias `$name`, but without modifying the actual stack in the 563 | /// program. 564 | /// See [top](trait.top.html) for examples 565 | #[macro_export] 566 | macro_rules! forth { 567 | ({ $EX:ty }) => { }; 568 | ({ $EX:ty } return) => { 569 | $EX 570 | }; 571 | ({ $EX:ty } return type $name:ident as $tok:tt $($token:tt)*) => { 572 | type $name = <$EX as $tok>::Result; 573 | forth!({ $EX } $($token)*) 574 | }; 575 | ({ $EX:ty } return type $name:ident $($token:tt)*) => { 576 | type $name = $EX; 577 | forth!({ $EX } $($token)*) 578 | }; 579 | ({ $EX:ty } . $($token:tt)*) => { 580 | println!("{}", <$EX as top>::Result::eval()); 581 | forth!({ <$EX as drop>::Result } $($token)*) 582 | }; 583 | ({ $EX:ty } : $name:ident $tok:tt $($token:tt)*) => { 584 | forth!(@compile { $EX } $name {()} ($tok) $($token)*) 585 | }; 586 | ({ $EX:ty } $tok:tt $($token:tt)*) => { 587 | forth!({ <$EX as $tok>::Result } $($token)*) 588 | }; 589 | (@compile { $EX:ty } $name:ident {$(($($cmdl:tt)*))*} ($($cmdr:tt)*) ; $($tbd:tt)*) => { 590 | pub trait $name { 591 | type Result; 592 | } 593 | impl $name for Stop { 594 | type Result = Self; 595 | } 596 | impl $name for Node 597 | where $( 598 | forth!({Self} $($cmdl)* return): $cmdr 599 | ),* 600 | { 601 | type Result = forth!({ Self } $($cmdr)* return); 602 | } 603 | forth!({ $EX } $($tbd)*) 604 | }; 605 | (@compile { $EX:ty } $name:ident {$(($($cmdl:tt)*))*} ($($cmdr:tt)*) $new:tt $($tbd:tt)*) => { 606 | forth!(@compile { $EX } $name {$(($($cmdl)*))* ($($cmdr)*)} ($($cmdr)* $new) $($tbd)*) 607 | }; 608 | (@subs ($($subst:tt)*) {$EX:ty}) => { 609 | forth!({$EX} $($subst)*) 610 | }; 611 | (@subs ($($subst:tt)*) {$EX:ty} ($($comment:tt)*) $($token:tt)*) => { 612 | forth!(@subs ($($subst)*) {$EX} $($token)*) 613 | }; 614 | (@subs ($($subst:tt)*) {$EX:ty} + $($token:tt)*) => { 615 | forth!(@subs ($($subst)* plus) {$EX} $($token)*) 616 | }; 617 | (@subs ($($subst:tt)*) {$EX:ty} - $($token:tt)*) => { 618 | forth!(@subs ($($subst)* minus) {$EX} $($token)*) 619 | }; 620 | (@subs ($($subst:tt)*) {$EX:ty} * $($token:tt)*) => { 621 | forth!(@subs ($($subst)* mult) {$EX} $($token)*) 622 | }; 623 | (@subs ($($subst:tt)*) {$EX:ty} % $($token:tt)*) => { 624 | forth!(@subs ($($subst)* modulo) {$EX} $($token)*) 625 | }; 626 | (@subs ($($subst:tt)*) {$EX:ty} = $($token:tt)*) => { 627 | forth!(@subs ($($subst)* eq) {$EX} $($token)*) 628 | }; 629 | (@subs ($($subst:tt)*) {$EX:ty} < $($token:tt)*) => { 630 | forth!(@subs ($($subst)* less) {$EX} $($token)*) 631 | }; 632 | (@subs ($($subst:tt)*) {$EX:ty} if $($token:tt)*) => { 633 | forth!(@subs ($($subst)* iff) {$EX} $($token)*) 634 | }; 635 | (@subs ($($subst:tt)*) {$EX:ty} else $($token:tt)*) => { 636 | forth!(@subs ($($subst)* elsef) {$EX} $($token)*) 637 | }; 638 | (@subs ($($subst:tt)*) {$EX:ty} 0 $($token:tt)*) => { 639 | forth!(@subs ($($subst)* zero) {$EX} $($token)*) 640 | }; 641 | (@subs ($($subst:tt)*) {$EX:ty} 1 $($token:tt)*) => { 642 | forth!(@subs ($($subst)* one) {$EX} $($token)*) 643 | }; 644 | (@subs ($($subst:tt)*) {$EX:ty} 2 $($token:tt)*) => { 645 | forth!(@subs ($($subst)* two) {$EX} $($token)*) 646 | }; 647 | (@subs ($($subst:tt)*) {$EX:ty} 3 $($token:tt)*) => { 648 | forth!(@subs ($($subst)* three) {$EX} $($token)*) 649 | }; 650 | (@subs ($($subst:tt)*) {$EX:ty} 4 $($token:tt)*) => { 651 | forth!(@subs ($($subst)* four) {$EX} $($token)*) 652 | }; 653 | (@subs ($($subst:tt)*) {$EX:ty} 5 $($token:tt)*) => { 654 | forth!(@subs ($($subst)* five) {$EX} $($token)*) 655 | }; 656 | (@subs ($($subst:tt)*) {$EX:ty} 6 $($token:tt)*) => { 657 | forth!(@subs ($($subst)* six) {$EX} $($token)*) 658 | }; 659 | (@subs ($($subst:tt)*) {$EX:ty} 7 $($token:tt)*) => { 660 | forth!(@subs ($($subst)* seven) {$EX} $($token)*) 661 | }; 662 | (@subs ($($subst:tt)*) {$EX:ty} 8 $($token:tt)*) => { 663 | forth!(@subs ($($subst)* eight) {$EX} $($token)*) 664 | }; 665 | (@subs ($($subst:tt)*) {$EX:ty} 9 $($token:tt)*) => { 666 | forth!(@subs ($($subst)* nine) {$EX} $($token)*) 667 | }; 668 | (@subs ($($subst:tt)*) {$EX:ty} 10 $($token:tt)*) => { 669 | forth!(@subs ($($subst)* ten) {$EX} $($token)*) 670 | }; 671 | (@subs ($($subst:tt)*) {$EX:ty} true $($token:tt)*) => { 672 | forth!(@subs ($($subst)* truef) {$EX} $($token)*) 673 | }; 674 | (@subs ($($subst:tt)*) {$EX:ty} false $($token:tt)*) => { 675 | forth!(@subs ($($subst)* falsef) {$EX} $($token)*) 676 | }; 677 | (@subs ($($subst:tt)*) {$EX:ty} $tok:tt $($token:tt)*) => { 678 | forth!(@subs ($($subst)* $tok) {$EX} $($token)*) 679 | }; 680 | ($($token:tt)*) => { 681 | forth!(@subs () { Empty } $($token)*) 682 | }; 683 | } 684 | --------------------------------------------------------------------------------