fps-lang

所属分类:游戏
开发工具:Rust
文件大小:0KB
下载次数:0
上传日期:2024-01-08 08:43:37
上 传 者sh-1993
说明:  一种“每秒帧数”模因语言,用于学习如何开发词法分析器、解析器、解释器和编译器
(A "frames per second" meme language to learn how to develop a lexer, parser, interpreter and compiler)

文件列表:
src/
Cargo.lock
Cargo.toml
LICENSE

# FPS Lang A `frames per second` meme programming language written in `Rust` The concept of this language is to execute statements on a `per frame` level The lexing/parsing concept is based on the book [Crafting Interpreters](https://craftinginterpreters.com/) The weird `FPS` part was just a silly idea I had when thinking about `frames per second` in video games All lexing and parsing was initally developed completelly manual without using any third-party libraries. I might change this in the future. Currently I'm not using any lifetimes or Arc/Rc/RefCell as I was too deep into development when I wanted to make this change. I might be adding this in the future in order to remove all those **ugly** `.clone()` ## Logic ### Frame concept \# represents a frame ```rust let a=1; # print(a); ## <- exit program on last frame ^ ^ | |_frame 1 -> 'print(a);' will be executed on frame 2 frame 0 -> 'let a = 1;' will be executed on frame 1 ``` ### Weird language And this is where `FPS Lang` shines at being `weird` ```rust // this is FRAME 0 print("printed at frame 1 - declared at frame 0"); let a = 0; #3 // frame 1 content will be spread out accross the next 3 frames - but special attention to the for loop! // this message will be printed out 3 times (at frames 2,3,4) print("printed at frames 2|3|4 - declared at frame 1"); // each for loop iteration is a new frame, which means the inner loop statements will executed for 6 frames -> 3 (frames) * 2 (range 0..=1) for 0..=1 { print("printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop"); a = a + 1; print(a); } # // frame 4 print("printed at frame 5 - declared at frame 4"); print(a); // should print 4 ## ``` output ```rust FPS 1 -> printed at frame 1 - declared at frame 0 FPS 2 -> printed at frames 2|3|4 - declared at frame 1 FPS 2 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 2 -> 1 // 'a' value - printed inside for loop FPS 3 -> printed at frames 2|3|4 - declared at frame 1 FPS 3 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 3 -> 2 // 'a' value - printed inside for loop FPS 4 -> printed at frames 2|3|4 - declared at frame 1 FPS 4 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 4 -> 3 // 'a' value - printed inside for loop FPS 5 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 5 -> 4 // 'a' value - printed inside for loop FPS 5 -> printed at frame 5 - declared at frame 4 FPS 5 -> 4 // 'a' value - printed at frame 5 (declared at frame 4) FPS 6 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 6 -> 5 // 'a' value - printed inside for loop FPS 7 -> printed at frames 2|3|4|5|6|7 - declared at frame 1 inside for loop FPS 7 -> 6 // 'a' value - printed inside for loop ``` ## Usage ```sh cargo run -- --help Usage: fps-lang.exe [OPTIONS] Options: -r, --repl Flag to access the REPL -h, --help Print help -V, --version Print version ``` ### Execute `Note` that currently it only executes the content of `sample.fps` file. I'll be adding a custom file input soon ```sh cargo run -- ``` ### REPL Start a REPL ```sh cargo run -- -r # REPL - FPS Lang # -------------------- Type '\q' to exit fps> ``` ```sh fps> let a = 0; print(a); ## FPS 1 -> 0 ``` ### Tests Execute the currently implemented tests ```sh cargo test running 23 tests test ast::environment::tests::declare ... ok test ast::environment::tests::assign ... ok test lexer::tests::comment ... ok test lexer::tests::unterminated_consumption ... ok test lexer::tests::numeric_literal ... ok test lexer::tests::single_char_tokens ... ok test parser::tests::test_comparison_paren ... ok test lexer::tests::types ... ok test lexer::tests::two_char_tokens ... ok test lexer::tests::identifer_literal ... ok test ast::environment::tests::declare_different_env ... ok test lexer::tests::keywords ... ok test parser::tests::declaration ... ok test interpreter::tests::multiple_frames ... ok test parser::tests::declaration_assign ... ok test parser::tests::declaration_print ... ok test parser::tests::test_addition ... ok test ast::expr::tests::pretty_print_ast ... ok test lexer::tests::string_literal ... ok test parser::tests::test_logical_and ... ok test parser::tests::test_logical_or ... ok test parser::tests::test_print_statement ... ok test parser::tests::test_comparison ... ok test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` ## Types Currently supported types | Type | Declaration | | -------------------- | ----------- | | Int | 1 | | Float | 1. or 1.0 | | String | "value" | | Boolean | true | | Range(int, int) | 0..1 | | RangeEqual(int, int) | 0..1= | | Null | null | ### Syntax #### Frame `#` represents a frame ```rust let a = 0; print(a); # print(a); ## ``` output ```rust FPS 1 -> 0 FPS 2 -> 0 ``` #### FPS Program end `##` represents the end of the program #### Declaration / Assignment Use `let` to declare a variable. ```rust let a = 0; ``` #### Range Use `..` surround by 2 digits to define a `Range` - `Range` is bound inclusively below and exclusively above Ranges can also be `RangeEqual` by adding a `=` sign to the range `0..=1` - `RangeEqual` is bound inclusively below and inclusively above. #### Logical operations ```rust let a = true && false; print(a); a = true || false; print(a); ## ``` output ```rust FPS 1 -> false FPS 1 -> true ``` #### For loop For loop iterations represent a frame. So, every statement inside a for loop will be executed x times across x frames ```rust for 0..2 { print("hello"); } ## ``` output ```rust FPS 1 -> hello FPS 2 -> hello ``` #### While loop ```rust let a = 1; while a < 3 { print(a); a = a + 1; } print(a); ## ``` output ```rust FPS 1 -> 1 FPS 1 -> 2 FPS 1 -> 3 ``` #### If/Else block ```rust if 0 == 1 { print("equals"); } else { print("not equals"); } ``` #### Block with scope logic ```rust let a = 1; { let b = 1; print(a + b); } ## ``` output ```rust FPS 1 -> 2 ``` ## Error handling For error handling in `Rust` I am using [anyhow](https://docs.rs/anyhow/latest/anyhow/) and [thiserror](https://docs.rs/thiserror/latest/thiserror/). Regarding `FPS Lang` I accumulate `lexer`, `parsing` or `interpreter` errors and show them to the user ```sh ERROR: Errors parsing: ["Invalid variable declaration: 'Could not consume: '\"Expected ';' after declaration\"''", "Could not consume: '\"Expected ';' after statement\"'"] ```

近期下载者

相关文件


收藏者