forked from natto1784/tricc
		
	
							
								
								
									
										50
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					name: CI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on: [push, pull_request, workflow_dispatch]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  checks:
 | 
				
			||||||
 | 
					    name: Checks
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 | 
					      - uses: cachix/install-nix-action@v20
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          extra_nix_config: |
 | 
				
			||||||
 | 
					            auto-optimise-store = true
 | 
				
			||||||
 | 
					            experimental-features = nix-command flakes
 | 
				
			||||||
 | 
					      - uses: cachix/cachix-action@v12
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pain
 | 
				
			||||||
 | 
					          authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: fmt check
 | 
				
			||||||
 | 
					        run: nix build .#checks.fmt -L
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: clippy check
 | 
				
			||||||
 | 
					        run: nix build .#checks.clippy -L
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					      - name: nextest check
 | 
				
			||||||
 | 
					        run: nix build .#checks.nextest -L
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: doc tests
 | 
				
			||||||
 | 
					        run: nix build .#checks.doc -L
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build:
 | 
				
			||||||
 | 
					    name: Build
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    needs: [ checks ]
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 | 
					      - uses: cachix/install-nix-action@v20
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          extra_nix_config: |
 | 
				
			||||||
 | 
					            auto-optimise-store = true
 | 
				
			||||||
 | 
					            experimental-features = nix-command flakes
 | 
				
			||||||
 | 
					      - uses: cachix/cachix-action@v12
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pain
 | 
				
			||||||
 | 
					          authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: fmt check
 | 
				
			||||||
 | 
					        run: nix build .#tricc -L
 | 
				
			||||||
							
								
								
									
										96
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										96
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							@@ -10,11 +10,11 @@
 | 
				
			|||||||
        "rust-overlay": "rust-overlay"
 | 
					        "rust-overlay": "rust-overlay"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1680584903,
 | 
					        "lastModified": 1688772518,
 | 
				
			||||||
        "narHash": "sha256-uraq+D3jcLzw/UVk0xMHcnfILfIMa0DLrtAEq2nNlxU=",
 | 
					        "narHash": "sha256-ol7gZxwvgLnxNSZwFTDJJ49xVY5teaSvF7lzlo3YQfM=",
 | 
				
			||||||
        "owner": "ipetkov",
 | 
					        "owner": "ipetkov",
 | 
				
			||||||
        "repo": "crane",
 | 
					        "repo": "crane",
 | 
				
			||||||
        "rev": "65d3f6a3970cd46bef5eedfd458300f72c56b3c5",
 | 
					        "rev": "8b08e96c9af8c6e3a2b69af5a7fa168750fcf88e",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -40,12 +40,15 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "flake-utils": {
 | 
					    "flake-utils": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "systems": "systems"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1678901627,
 | 
					        "lastModified": 1687709756,
 | 
				
			||||||
        "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
 | 
					        "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "flake-utils",
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
        "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
 | 
					        "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -55,12 +58,15 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "flake-utils_2": {
 | 
					    "flake-utils_2": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "systems": "systems_2"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1678901627,
 | 
					        "lastModified": 1689068808,
 | 
				
			||||||
        "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
 | 
					        "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "flake-utils",
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
        "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
 | 
					        "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -70,12 +76,15 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "flake-utils_3": {
 | 
					    "flake-utils_3": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "systems": "systems_3"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1659877975,
 | 
					        "lastModified": 1681202837,
 | 
				
			||||||
        "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
 | 
					        "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "flake-utils",
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
        "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
 | 
					        "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -86,11 +95,11 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "nixpkgs": {
 | 
					    "nixpkgs": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1680724564,
 | 
					        "lastModified": 1688392541,
 | 
				
			||||||
        "narHash": "sha256-eeUUGOTKTelYKDbUxKs0V7GUa186L2fym7jM2QQ4Oss=",
 | 
					        "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
 | 
				
			||||||
        "owner": "NixOS",
 | 
					        "owner": "NixOS",
 | 
				
			||||||
        "repo": "nixpkgs",
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
        "rev": "36adaa6aaa6b03e59102df0c1b12cdc3f23fd112",
 | 
					        "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -120,11 +129,11 @@
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1680488274,
 | 
					        "lastModified": 1688351637,
 | 
				
			||||||
        "narHash": "sha256-0vYMrZDdokVmPQQXtFpnqA2wEgCCUXf5a3dDuDVshn0=",
 | 
					        "narHash": "sha256-CLTufJ29VxNOIZ8UTg0lepsn3X03AmopmaLTTeHDCL4=",
 | 
				
			||||||
        "owner": "oxalica",
 | 
					        "owner": "oxalica",
 | 
				
			||||||
        "repo": "rust-overlay",
 | 
					        "repo": "rust-overlay",
 | 
				
			||||||
        "rev": "7ec2ff598a172c6e8584457167575b3a1a5d80d8",
 | 
					        "rev": "f9b92316727af9e6c7fee4a761242f7f46880329",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -141,11 +150,11 @@
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1680660688,
 | 
					        "lastModified": 1690252178,
 | 
				
			||||||
        "narHash": "sha256-XeQTCxWBR0Ai1VMzI5ZXYpA2lu1F8FzZKjw8RtByZOg=",
 | 
					        "narHash": "sha256-9oEz822bvbHobfCUjJLDor2BqW3I5tycIauzDlzOALY=",
 | 
				
			||||||
        "owner": "oxalica",
 | 
					        "owner": "oxalica",
 | 
				
			||||||
        "repo": "rust-overlay",
 | 
					        "repo": "rust-overlay",
 | 
				
			||||||
        "rev": "2f40052be98347b479c820c00fb2fc1d87b3aa28",
 | 
					        "rev": "8d64353ca827002fb8459e44d49116c78d868eba",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -153,6 +162,51 @@
 | 
				
			|||||||
        "repo": "rust-overlay",
 | 
					        "repo": "rust-overlay",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "systems": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1681028828,
 | 
				
			||||||
 | 
					        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "systems_2": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1681028828,
 | 
				
			||||||
 | 
					        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "systems_3": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1681028828,
 | 
				
			||||||
 | 
					        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "root": "root",
 | 
					  "root": "root",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								flake.nix
									
									
									
									
									
								
							@@ -38,25 +38,34 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        tricc = craneLib.buildPackage (commonArgs // {
 | 
					        tricc = craneLib.buildPackage (commonArgs // {
 | 
				
			||||||
          inherit cargoArtifacts;
 | 
					          inherit cargoArtifacts;
 | 
				
			||||||
 | 
					          doCheck = false;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      in
 | 
					      in
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        checks = {
 | 
					 | 
				
			||||||
          inherit tricc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          clippy = craneLib.cargoClippy (commonArgs // {
 | 
					 | 
				
			||||||
            inherit cargoArtifacts;
 | 
					 | 
				
			||||||
            cargoClippyExtraArgs = "--all-targets -- --deny warnings";
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          fmt = craneLib.cargoFmt {
 | 
					 | 
				
			||||||
            inherit src;
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        packages = {
 | 
					        packages = {
 | 
				
			||||||
          inherit tricc;
 | 
					          inherit tricc;
 | 
				
			||||||
          default = tricc;
 | 
					          default = tricc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # not using flake checks to run them individually
 | 
				
			||||||
 | 
					          checks = {
 | 
				
			||||||
 | 
					            clippy = craneLib.cargoClippy (commonArgs // {
 | 
				
			||||||
 | 
					              inherit cargoArtifacts;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fmt = craneLib.cargoFmt {
 | 
				
			||||||
 | 
					              inherit src;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            doc = craneLib.cargoDoc (commonArgs // {
 | 
				
			||||||
 | 
					              inherit cargoArtifacts;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            nextest = craneLib.cargoNextest (commonArgs // {
 | 
				
			||||||
 | 
					              inherit cargoArtifacts;
 | 
				
			||||||
 | 
					              partitions = 1;
 | 
				
			||||||
 | 
					              partitionType = "count";
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        devShells.default = pkgs.mkShell {
 | 
					        devShells.default = pkgs.mkShell {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,3 @@
 | 
				
			|||||||
[toolchain]
 | 
					[toolchain]
 | 
				
			||||||
channel = "nightly-2023-04-01"
 | 
					channel = "nightly-2023-07-15"
 | 
				
			||||||
components = [ "rustfmt", "clippy", "rust-analyzer", "rust-src" ]
 | 
					components = [ "rustfmt", "clippy", "rust-analyzer", "rust-src" ]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					comment_width = 99
 | 
				
			||||||
 | 
					format_code_in_doc_comments = true
 | 
				
			||||||
 | 
					imports_granularity = "Module"
 | 
				
			||||||
 | 
					imports_layout = "Vertical"
 | 
				
			||||||
 | 
					wrap_comments = true
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/args.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/args.rs
									
									
									
									
									
								
							@@ -4,7 +4,7 @@ use std::process::exit;
 | 
				
			|||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
 | 
					const VERSION: &str = env!("CARGO_PKG_VERSION");
 | 
				
			||||||
const CRATE: &str = env!("CARGO_CRATE_NAME");
 | 
					const CRATE: &str = env!("CARGO_CRATE_NAME");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// naive argument handling
 | 
					/// A naive argument handler
 | 
				
			||||||
#[derive(Default)]
 | 
					#[derive(Default)]
 | 
				
			||||||
pub struct Args {
 | 
					pub struct Args {
 | 
				
			||||||
    version: bool,
 | 
					    version: bool,
 | 
				
			||||||
@@ -12,13 +12,12 @@ pub struct Args {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Args {
 | 
					impl Args {
 | 
				
			||||||
 | 
					    /// Creates a new [`Args`] instance
 | 
				
			||||||
    pub fn new() -> Args {
 | 
					    pub fn new() -> Args {
 | 
				
			||||||
        Args {
 | 
					        Args::default()
 | 
				
			||||||
            version: false,
 | 
					 | 
				
			||||||
            file: None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Checks for various arguments
 | 
				
			||||||
    pub fn handle(&mut self) {
 | 
					    pub fn handle(&mut self) {
 | 
				
			||||||
        let args: Vec<String> = env::args().collect();
 | 
					        let args: Vec<String> = env::args().collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +52,8 @@ impl Args {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Fetches the file from the arguments.
 | 
				
			||||||
 | 
					    /// Panics if there is no file in the arguments
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_file(self) -> String {
 | 
					    pub fn get_file(self) -> String {
 | 
				
			||||||
        self.file.expect("no file supplied!")
 | 
					        self.file.expect("no file supplied!")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										475
									
								
								src/lexer.rs
									
									
									
									
									
								
							
							
						
						
									
										475
									
								
								src/lexer.rs
									
									
									
									
									
								
							@@ -1,13 +1,22 @@
 | 
				
			|||||||
use std::{iter, str};
 | 
					use std::collections::VecDeque;
 | 
				
			||||||
 | 
					use std::iter::Peekable;
 | 
				
			||||||
 | 
					use std::rc::Rc;
 | 
				
			||||||
 | 
					use std::str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					/// All token literals
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// TODO: Add string
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub enum TokenLiteral {
 | 
					pub enum TokenLiteral {
 | 
				
			||||||
    Int,
 | 
					    Int,
 | 
				
			||||||
    Float,
 | 
					    Float,
 | 
				
			||||||
    Char,
 | 
					    Char,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					/// All token symbols
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// TODO: Maybe add *
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub enum TokenSymbol {
 | 
					pub enum TokenSymbol {
 | 
				
			||||||
    // operators
 | 
					    // operators
 | 
				
			||||||
    Plus,
 | 
					    Plus,
 | 
				
			||||||
@@ -58,10 +67,16 @@ pub enum TokenSymbol {
 | 
				
			|||||||
    Hash,
 | 
					    Hash,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					/// All token keywod
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub enum TokenKeyword {
 | 
					pub enum TokenKeyword {
 | 
				
			||||||
    Let,
 | 
					    // parents
 | 
				
			||||||
    Fn,
 | 
					    Fn,
 | 
				
			||||||
 | 
					    Class,
 | 
				
			||||||
 | 
					    Module,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // statements
 | 
				
			||||||
 | 
					    Let,
 | 
				
			||||||
    Ret,
 | 
					    Ret,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // conditionals
 | 
					    // conditionals
 | 
				
			||||||
@@ -69,10 +84,10 @@ pub enum TokenKeyword {
 | 
				
			|||||||
    Else,
 | 
					    Else,
 | 
				
			||||||
    Elif,
 | 
					    Elif,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // loops
 | 
					    // control flow
 | 
				
			||||||
    While,
 | 
					    Loop,
 | 
				
			||||||
    Do,
 | 
					    Break,
 | 
				
			||||||
    For,
 | 
					    Continue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // primitives
 | 
					    // primitives
 | 
				
			||||||
    Int,
 | 
					    Int,
 | 
				
			||||||
@@ -80,7 +95,10 @@ pub enum TokenKeyword {
 | 
				
			|||||||
    Char,
 | 
					    Char,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					/// All token delimiters
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// TODO: Maybe add \[ and \]
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub enum TokenDelimiter {
 | 
					pub enum TokenDelimiter {
 | 
				
			||||||
    BraceOpen,
 | 
					    BraceOpen,
 | 
				
			||||||
    BraceClose,
 | 
					    BraceClose,
 | 
				
			||||||
@@ -88,31 +106,70 @@ pub enum TokenDelimiter {
 | 
				
			|||||||
    ParenClose,
 | 
					    ParenClose,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					/// All tokens
 | 
				
			||||||
pub enum Token<'a> {
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
 | 
					pub enum TokenKind {
 | 
				
			||||||
    Newline,
 | 
					    Newline,
 | 
				
			||||||
    Literal(TokenLiteral, &'a str),
 | 
					    Eof,
 | 
				
			||||||
 | 
					    Literal(TokenLiteral),
 | 
				
			||||||
    Symbol(TokenSymbol),
 | 
					    Symbol(TokenSymbol),
 | 
				
			||||||
    Keyword(TokenKeyword),
 | 
					    Keyword(TokenKeyword),
 | 
				
			||||||
    Delimiter(TokenDelimiter),
 | 
					    Delimiter(TokenDelimiter),
 | 
				
			||||||
    Identifier(&'a str),
 | 
					    Identifier,
 | 
				
			||||||
 | 
					    Invalid,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct Token {
 | 
				
			||||||
 | 
					    pub kind: TokenKind,
 | 
				
			||||||
 | 
					    /// Holds the reference to the tokenized string
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// For example, if `kind` is of type [`TokenKind::Identifier`], this would contain the value
 | 
				
			||||||
 | 
					    /// of that identifier
 | 
				
			||||||
 | 
					    pub val: Rc<str>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Lexer<'a> {
 | 
					pub struct Lexer<'a> {
 | 
				
			||||||
    file: &'a str,
 | 
					    /// The entire text to be tokenized
 | 
				
			||||||
    text: &'a str,
 | 
					    text: &'a str,
 | 
				
			||||||
    chars: iter::Peekable<str::Chars<'a>>,
 | 
					    /// A peekable iterate for `text`
 | 
				
			||||||
    line: usize,
 | 
					    chars: Peekable<str::Chars<'a>>,
 | 
				
			||||||
    start: usize,
 | 
					    /// A peekable double ended queue for the tokens
 | 
				
			||||||
 | 
					    tokens: VecDeque<Token>,
 | 
				
			||||||
 | 
					    /// Current line number
 | 
				
			||||||
 | 
					    pub line: usize,
 | 
				
			||||||
 | 
					    /// Start character index for the current token
 | 
				
			||||||
 | 
					    pub start: usize,
 | 
				
			||||||
 | 
					    /// End character index for the current token
 | 
				
			||||||
    end: usize,
 | 
					    end: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Lexer<'a> {
 | 
					impl<'a> Lexer<'a> {
 | 
				
			||||||
    pub fn new(file: &'a str, contents: &'a str) -> Lexer<'a> {
 | 
					    /// Creates a new [`Lexer`] instance with the provided content.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The `Lexer` is responsible for tokenizing the given text, making it easier to
 | 
				
			||||||
 | 
					    /// perform various parsing operations.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Arguments
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// * `content`: The text to tokenize.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Returns
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// A new instance of `Lexer` initialized with the provided `content`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Example
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    /// use tricc::lexer::Lexer;
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// let lexer = Lexer::new("let example: int = 4");
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    pub fn new(content: &'a str) -> Self {
 | 
				
			||||||
        Lexer {
 | 
					        Lexer {
 | 
				
			||||||
            file,
 | 
					            text: content,
 | 
				
			||||||
            text: contents,
 | 
					            chars: content.chars().peekable(),
 | 
				
			||||||
            chars: contents.chars().peekable(),
 | 
					            tokens: VecDeque::new(),
 | 
				
			||||||
            line: 1,
 | 
					            line: 1,
 | 
				
			||||||
            start: 0,
 | 
					            start: 0,
 | 
				
			||||||
            end: 0,
 | 
					            end: 0,
 | 
				
			||||||
@@ -120,49 +177,63 @@ impl<'a> Lexer<'a> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    fn error(&self) {
 | 
					    fn new_token(&self, kind: TokenKind) -> Token {
 | 
				
			||||||
        eprintln!("error lexing \"{}:{}:{}\"", self.file, self.line, self.end);
 | 
					        Token {
 | 
				
			||||||
 | 
					            kind,
 | 
				
			||||||
 | 
					            val: Rc::from(&self.text[self.start..self.end]),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn error(&self, msg: &str) {
 | 
				
			||||||
 | 
					        eprintln!("Lexer: {}, at \"{}:{}\"", msg, self.line, self.end);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn peek(&mut self) -> Option<&char> {
 | 
				
			||||||
 | 
					        self.chars.peek()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
    fn next(&mut self) -> Option<char> {
 | 
					    fn next(&mut self) -> Option<char> {
 | 
				
			||||||
        self.end += 1;
 | 
					        self.end += 1;
 | 
				
			||||||
        self.chars.next()
 | 
					        self.chars.next()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn skip(&mut self, c: char) {
 | 
					    fn skip_whitespace(&mut self) {
 | 
				
			||||||
        if self.next() != Some(c) {
 | 
					        let mut ignore_nl: bool = false;
 | 
				
			||||||
            self.error();
 | 
					 | 
				
			||||||
            panic!("expected {}", c);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn escape_newline(&mut self) {
 | 
					        while let Some(c) = self.peek() {
 | 
				
			||||||
        while let Some(c) = self.chars.peek() {
 | 
					 | 
				
			||||||
            match c {
 | 
					            match c {
 | 
				
			||||||
                '\r' | '\t' | ' ' => {
 | 
					                '\r' | '\t' | ' ' => {
 | 
				
			||||||
                    self.next();
 | 
					                    self.next();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                '\n' => {
 | 
					                '\n' => {
 | 
				
			||||||
                    self.next();
 | 
					                    if ignore_nl {
 | 
				
			||||||
                    break;
 | 
					                        ignore_nl = false;
 | 
				
			||||||
 | 
					                        self.next();
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => {
 | 
					                '\\' => {
 | 
				
			||||||
                    self.error();
 | 
					                    self.next();
 | 
				
			||||||
                    panic!("expected newline");
 | 
					                    ignore_nl = true;
 | 
				
			||||||
                },
 | 
					                }
 | 
				
			||||||
 | 
					                _ => break,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_numeric(&mut self) -> Token<'a> {
 | 
					    fn get_numeric(&mut self) -> Token {
 | 
				
			||||||
        let mut is_float: bool = false;
 | 
					        let mut is_float: bool = false;
 | 
				
			||||||
        while let Some(c) = self.chars.peek() {
 | 
					        while let Some(c) = self.peek() {
 | 
				
			||||||
            match c {
 | 
					            match c {
 | 
				
			||||||
                '0'..='9' => {}
 | 
					                '0'..='9' => {}
 | 
				
			||||||
                '.' => {
 | 
					                '.' => {
 | 
				
			||||||
                    if is_float {
 | 
					                    if is_float {
 | 
				
			||||||
                        self.error();
 | 
					                        self.error("Multiple decimals encountered");
 | 
				
			||||||
                        panic!("multiple decimals encountered")
 | 
					                        return self.new_token(TokenKind::Invalid);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    is_float = true;
 | 
					                    is_float = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -171,62 +242,78 @@ impl<'a> Lexer<'a> {
 | 
				
			|||||||
            self.next();
 | 
					            self.next();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Token::Literal(
 | 
					        self.new_token(TokenKind::Literal(if is_float {
 | 
				
			||||||
            if is_float {
 | 
					            TokenLiteral::Float
 | 
				
			||||||
                TokenLiteral::Float
 | 
					        } else {
 | 
				
			||||||
            } else {
 | 
					            TokenLiteral::Int
 | 
				
			||||||
                TokenLiteral::Int
 | 
					        }))
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            &self.text[self.start..self.end],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_char(&mut self) -> Token<'a> {
 | 
					    fn get_char(&mut self) -> Token {
 | 
				
			||||||
        self.skip('\'');
 | 
					        // skip '
 | 
				
			||||||
 | 
					        self.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if matches!(self.next(), Some('\'') | None) {
 | 
					        if matches!(self.next(), Some('\'') | None) {
 | 
				
			||||||
            self.error();
 | 
					            self.error("Expected character literal");
 | 
				
			||||||
            panic!("A character literal cannot be empty");
 | 
					            return self.new_token(TokenKind::Invalid);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.skip('\'');
 | 
					        // skip '
 | 
				
			||||||
 | 
					        self.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Token::Literal(TokenLiteral::Char, &self.text[self.start + 1..self.end - 1])
 | 
					        self.new_token(TokenKind::Literal(TokenLiteral::Char))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_delimiter(&mut self) -> Token<'a> {
 | 
					    fn get_alphanumeric(&mut self) -> Token {
 | 
				
			||||||
        use Token::Delimiter;
 | 
					        while let Some(c) = self.peek() {
 | 
				
			||||||
        use TokenDelimiter::*;
 | 
					            match c {
 | 
				
			||||||
 | 
					                'a'..='z' | 'A'..='Z' | '0'..='9' => {}
 | 
				
			||||||
        match self.next() {
 | 
					                _ => break,
 | 
				
			||||||
            Some(c) => match c {
 | 
					 | 
				
			||||||
                '{' => Delimiter(BraceOpen),
 | 
					 | 
				
			||||||
                '}' => Delimiter(BraceClose),
 | 
					 | 
				
			||||||
                '(' => Delimiter(ParenOpen),
 | 
					 | 
				
			||||||
                ')' => Delimiter(ParenClose),
 | 
					 | 
				
			||||||
                _ => {
 | 
					 | 
				
			||||||
                    self.error();
 | 
					 | 
				
			||||||
                    panic!("expected delimiter");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => {
 | 
					 | 
				
			||||||
                self.error();
 | 
					 | 
				
			||||||
                panic!("expected delimiter");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            self.next();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        use TokenKeyword::*;
 | 
				
			||||||
 | 
					        use TokenKind::Keyword;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.new_token(match &self.text[self.start..self.end] {
 | 
				
			||||||
 | 
					            "fn" => Keyword(Fn),
 | 
				
			||||||
 | 
					            "class" => Keyword(Class),
 | 
				
			||||||
 | 
					            "module" => Keyword(Module),
 | 
				
			||||||
 | 
					            "let" => Keyword(Let),
 | 
				
			||||||
 | 
					            "ret" => Keyword(Ret),
 | 
				
			||||||
 | 
					            "if" => Keyword(If),
 | 
				
			||||||
 | 
					            "else" => Keyword(Else),
 | 
				
			||||||
 | 
					            "elif" => Keyword(Elif),
 | 
				
			||||||
 | 
					            "loop" => Keyword(Loop),
 | 
				
			||||||
 | 
					            "break" => Keyword(Break),
 | 
				
			||||||
 | 
					            "continue" => Keyword(Continue),
 | 
				
			||||||
 | 
					            "int" => Keyword(Int),
 | 
				
			||||||
 | 
					            "float" => Keyword(Float),
 | 
				
			||||||
 | 
					            "char" => Keyword(Char),
 | 
				
			||||||
 | 
					            _ => TokenKind::Identifier,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_symbol(&mut self) -> Token<'a> {
 | 
					    fn get_symbol(&mut self) -> Token {
 | 
				
			||||||
        use Token::Symbol;
 | 
					        let c = self.next().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        use TokenDelimiter::*;
 | 
				
			||||||
 | 
					        use TokenKind::{
 | 
				
			||||||
 | 
					            Delimiter,
 | 
				
			||||||
 | 
					            Symbol,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        use TokenSymbol::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // handle +, +=, -, -=, *, *=, /, /=, %, %=, ^, ^=, !, !=
 | 
					        // handle +, +=, -, -=, *, *=, /, /=, %, %=, ^, ^=, !, !=
 | 
				
			||||||
        macro_rules! token_symbol_eq {
 | 
					        macro_rules! token_symbol_eq {
 | 
				
			||||||
            ($a:expr, $b:expr) => {
 | 
					            ($a:expr, $b:expr) => {
 | 
				
			||||||
                if self.chars.peek() == Some(&'=') {
 | 
					                match self.peek() {
 | 
				
			||||||
                    self.next();
 | 
					                    Some('=') => {
 | 
				
			||||||
                    Symbol($b)
 | 
					                        self.next();
 | 
				
			||||||
                } else {
 | 
					                        Symbol($b)
 | 
				
			||||||
                    Symbol($a)
 | 
					                    }
 | 
				
			||||||
 | 
					                    _ => Symbol($a),
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -234,7 +321,7 @@ impl<'a> Lexer<'a> {
 | 
				
			|||||||
        // handle &, |, ||, &&, &=, |=
 | 
					        // handle &, |, ||, &&, &=, |=
 | 
				
			||||||
        macro_rules! token_symbol_logical {
 | 
					        macro_rules! token_symbol_logical {
 | 
				
			||||||
            ($a:expr, $b:expr, $c:expr, $d:expr) => {
 | 
					            ($a:expr, $b:expr, $c:expr, $d:expr) => {
 | 
				
			||||||
                match self.chars.peek() {
 | 
					                match self.peek() {
 | 
				
			||||||
                    Some('=') => {
 | 
					                    Some('=') => {
 | 
				
			||||||
                        self.next();
 | 
					                        self.next();
 | 
				
			||||||
                        Symbol($c)
 | 
					                        Symbol($c)
 | 
				
			||||||
@@ -251,7 +338,7 @@ impl<'a> Lexer<'a> {
 | 
				
			|||||||
        // handle <, <=, >, >=, <<, >>, <<=, >>=
 | 
					        // handle <, <=, >, >=, <<, >>, <<=, >>=
 | 
				
			||||||
        macro_rules! token_symbol_compare {
 | 
					        macro_rules! token_symbol_compare {
 | 
				
			||||||
            ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
 | 
					            ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
 | 
				
			||||||
                match self.chars.peek() {
 | 
					                match self.peek() {
 | 
				
			||||||
                    Some('=') => {
 | 
					                    Some('=') => {
 | 
				
			||||||
                        self.next();
 | 
					                        self.next();
 | 
				
			||||||
                        Symbol($d)
 | 
					                        Symbol($d)
 | 
				
			||||||
@@ -265,99 +352,155 @@ impl<'a> Lexer<'a> {
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        use TokenSymbol::*;
 | 
					        let typ = match c {
 | 
				
			||||||
 | 
					            '{' => Delimiter(BraceOpen),
 | 
				
			||||||
        match self.next() {
 | 
					            '}' => Delimiter(BraceClose),
 | 
				
			||||||
            Some(c) => match c {
 | 
					            '(' => Delimiter(ParenOpen),
 | 
				
			||||||
                '+' => token_symbol_eq!(Plus, PlusEq),
 | 
					            ')' => Delimiter(ParenClose),
 | 
				
			||||||
                '-' => token_symbol_eq!(Minus, MinusEq),
 | 
					            '+' => token_symbol_eq!(Plus, PlusEq),
 | 
				
			||||||
                '*' => token_symbol_eq!(Star, StarEq),
 | 
					            '-' => token_symbol_eq!(Minus, MinusEq),
 | 
				
			||||||
                '/' => token_symbol_eq!(Slash, SlashEq),
 | 
					            '*' => token_symbol_eq!(Star, StarEq),
 | 
				
			||||||
                '%' => token_symbol_eq!(Percent, PercentEq),
 | 
					            '/' => token_symbol_eq!(Slash, SlashEq),
 | 
				
			||||||
                '^' => token_symbol_eq!(Caret, CaretEq),
 | 
					            '%' => token_symbol_eq!(Percent, PercentEq),
 | 
				
			||||||
                '!' => token_symbol_eq!(Not, Ne),
 | 
					            '^' => token_symbol_eq!(Caret, CaretEq),
 | 
				
			||||||
                '=' => token_symbol_eq!(Eq, EqEq),
 | 
					            '!' => token_symbol_eq!(Not, Ne),
 | 
				
			||||||
                '&' => token_symbol_logical!(And, AndAnd, AndEq, '&'),
 | 
					            '=' => token_symbol_eq!(Eq, EqEq),
 | 
				
			||||||
                '|' => token_symbol_logical!(Or, OrOr, OrEq, '|'),
 | 
					            '&' => token_symbol_logical!(And, AndAnd, AndEq, '&'),
 | 
				
			||||||
                '<' => token_symbol_compare!(Lt, Shl, ShlEq, LtEq, '<'),
 | 
					            '|' => token_symbol_logical!(Or, OrOr, OrEq, '|'),
 | 
				
			||||||
                '>' => token_symbol_compare!(Gt, Shr, ShrEq, GtEq, '>'),
 | 
					            '<' => token_symbol_compare!(Lt, Shl, ShlEq, LtEq, '<'),
 | 
				
			||||||
                '~' => Symbol(Tilde),
 | 
					            '>' => token_symbol_compare!(Gt, Shr, ShrEq, GtEq, '>'),
 | 
				
			||||||
                ':' => Symbol(Colon),
 | 
					            '~' => Symbol(Tilde),
 | 
				
			||||||
                '.' => Symbol(Dot),
 | 
					            ':' => Symbol(Colon),
 | 
				
			||||||
                '#' => Symbol(Hash),
 | 
					            '.' => Symbol(Dot),
 | 
				
			||||||
                _ => {
 | 
					            '#' => Symbol(Hash),
 | 
				
			||||||
                    self.error();
 | 
					            _ => {
 | 
				
			||||||
                    panic!("expected symbol");
 | 
					                self.error("Unknown character encountered");
 | 
				
			||||||
                }
 | 
					                TokenKind::Invalid
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => {
 | 
					 | 
				
			||||||
                self.error();
 | 
					 | 
				
			||||||
                panic!("expected symbol");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        };
 | 
				
			||||||
 | 
					        self.new_token(typ)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_alphanumeric(&mut self) -> Token<'a> {
 | 
					    fn lex(&mut self) {
 | 
				
			||||||
        while let Some(c) = self.chars.peek() {
 | 
					        self.skip_whitespace();
 | 
				
			||||||
 | 
					        self.start = self.end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let token = if let Some(c) = self.peek() {
 | 
				
			||||||
            match c {
 | 
					            match c {
 | 
				
			||||||
                'a'..='z' | 'A'..='Z' | '0'..='9' => {}
 | 
					 | 
				
			||||||
                _ => break,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            self.next();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        use Token::Keyword;
 | 
					 | 
				
			||||||
        use TokenKeyword::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        match &self.text[self.start..self.end] {
 | 
					 | 
				
			||||||
            "let" => Keyword(Let),
 | 
					 | 
				
			||||||
            "fn" => Keyword(Fn),
 | 
					 | 
				
			||||||
            "ret" => Keyword(Ret),
 | 
					 | 
				
			||||||
            "if" => Keyword(If),
 | 
					 | 
				
			||||||
            "else" => Keyword(Else),
 | 
					 | 
				
			||||||
            "elif" => Keyword(Elif),
 | 
					 | 
				
			||||||
            "while" => Keyword(While),
 | 
					 | 
				
			||||||
            "do" => Keyword(Do),
 | 
					 | 
				
			||||||
            "for" => Keyword(For),
 | 
					 | 
				
			||||||
            "int" => Keyword(Int),
 | 
					 | 
				
			||||||
            "float" => Keyword(Float),
 | 
					 | 
				
			||||||
            "char" => Keyword(Char),
 | 
					 | 
				
			||||||
            _ => Token::Identifier(&self.text[self.start..self.end]),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn lex(&mut self) -> Vec<Token<'a>> {
 | 
					 | 
				
			||||||
        let mut tokens: Vec<Token> = Vec::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while let Some(c) = self.chars.peek() {
 | 
					 | 
				
			||||||
            match c {
 | 
					 | 
				
			||||||
                ' ' | '\r' | '\t' => {
 | 
					 | 
				
			||||||
                    self.next();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                '\\' => {
 | 
					 | 
				
			||||||
                    self.next();
 | 
					 | 
				
			||||||
                    self.escape_newline();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                '\n' => {
 | 
					                '\n' => {
 | 
				
			||||||
                    tokens.push(Token::Newline);
 | 
					 | 
				
			||||||
                    self.next();
 | 
					 | 
				
			||||||
                    self.line += 1;
 | 
					                    self.line += 1;
 | 
				
			||||||
 | 
					                    self.new_token(TokenKind::Newline)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                '0'..='9' => tokens.push(self.get_numeric()),
 | 
					                '0'..='9' => self.get_numeric(),
 | 
				
			||||||
                '\'' => tokens.push(self.get_char()),
 | 
					                'a'..='z' | 'A'..='Z' => self.get_alphanumeric(),
 | 
				
			||||||
                '{' | '}' | '(' | ')' => tokens.push(self.get_delimiter()),
 | 
					                '\'' => self.get_char(),
 | 
				
			||||||
                '+' | '-' | '*' | '/' | '%' | '^' | '~' | '&' | '|' | '!' | '<' | '>' | '='
 | 
					                _ => self.get_symbol(),
 | 
				
			||||||
                | ':' | '.' | '#' => tokens.push(self.get_symbol()),
 | 
					 | 
				
			||||||
                'a'..='z' | 'A'..='Z' => tokens.push(self.get_alphanumeric()),
 | 
					 | 
				
			||||||
                _ => {
 | 
					 | 
				
			||||||
                    self.error();
 | 
					 | 
				
			||||||
                    panic!("unknown character encountered");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.new_token(TokenKind::Eof)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.tokens.push_back(token);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.start = self.end;
 | 
					    /// Peeks at the next token and returns a reference to it
 | 
				
			||||||
 | 
					    pub fn peek_token(&mut self) -> &Token {
 | 
				
			||||||
 | 
					        if self.tokens.is_empty() {
 | 
				
			||||||
 | 
					            self.lex();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        &self.tokens[0]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tokens
 | 
					    /// Returns the next token, moving the lexer forward
 | 
				
			||||||
 | 
					    pub fn next_token(&mut self) -> Token {
 | 
				
			||||||
 | 
					        if self.tokens.is_empty() {
 | 
				
			||||||
 | 
					            self.lex();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.tokens.pop_front().unwrap()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_peek_next() {
 | 
				
			||||||
 | 
					    let mut lexer = Lexer::new("test01");
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), Some(&'t'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('t'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), Some(&'e'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), Some(&'e'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('e'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('s'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('t'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('0'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), Some(&'1'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), Some('1'));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), None);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next(), None);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek(), None);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_tokens_1() {
 | 
				
			||||||
 | 
					    let mut lexer = Lexer::new("let test02 = 4 << 1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use TokenKind::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Keyword(TokenKeyword::Let));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Keyword(TokenKeyword::Let));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut token = lexer.next_token();
 | 
				
			||||||
 | 
					    assert_eq!(token.kind, Identifier);
 | 
				
			||||||
 | 
					    assert_eq!(*token.val, *"test02");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Symbol(TokenSymbol::Eq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    token = lexer.next_token();
 | 
				
			||||||
 | 
					    assert_eq!(token.kind, Literal(TokenLiteral::Int));
 | 
				
			||||||
 | 
					    assert_eq!(*token.val, *"4");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Symbol(TokenSymbol::Shl));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Literal(TokenLiteral::Int));
 | 
				
			||||||
 | 
					    assert_eq!(*lexer.peek_token().val, *"1");
 | 
				
			||||||
 | 
					    token = lexer.next_token();
 | 
				
			||||||
 | 
					    assert_eq!(token.kind, Literal(TokenLiteral::Int));
 | 
				
			||||||
 | 
					    assert_eq!(*token.val, *"1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Eof);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Eof);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Eof);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Eof);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_tokens_2() {
 | 
				
			||||||
 | 
					    let mut lexer = Lexer::new("let test03: char = 'h'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use TokenKind::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Keyword(TokenKeyword::Let));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Keyword(TokenKeyword::Let));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut token = lexer.next_token();
 | 
				
			||||||
 | 
					    assert_eq!(token.kind, Identifier);
 | 
				
			||||||
 | 
					    assert_eq!(*token.val, *"test03");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Symbol(TokenSymbol::Colon));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Keyword(TokenKeyword::Char));
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Symbol(TokenSymbol::Eq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Literal(TokenLiteral::Char));
 | 
				
			||||||
 | 
					    assert_eq!(*lexer.peek_token().val, *"'h'");
 | 
				
			||||||
 | 
					    token = lexer.next_token();
 | 
				
			||||||
 | 
					    assert_eq!(token.kind, Literal(TokenLiteral::Char));
 | 
				
			||||||
 | 
					    assert_eq!(*token.val, *"'h'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, Eof);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, Eof);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_tokens_3() {
 | 
				
			||||||
 | 
					    let mut lexer = Lexer::new("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(lexer.peek_token().kind, TokenKind::Eof);
 | 
				
			||||||
 | 
					    assert_eq!(lexer.next_token().kind, TokenKind::Eof);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,8 +1,13 @@
 | 
				
			|||||||
use std::fs;
 | 
					use std::{
 | 
				
			||||||
use std::panic;
 | 
					    fs,
 | 
				
			||||||
 | 
					    panic,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use tricc::args::Args;
 | 
					use tricc::args::Args;
 | 
				
			||||||
use tricc::lexer::Lexer;
 | 
					use tricc::lexer::{
 | 
				
			||||||
 | 
					    Lexer,
 | 
				
			||||||
 | 
					    TokenKind,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    panic::set_hook(Box::new(|panic_info| {
 | 
					    panic::set_hook(Box::new(|panic_info| {
 | 
				
			||||||
@@ -21,14 +26,15 @@ fn main() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut args = Args::new();
 | 
					    let mut args = Args::default();
 | 
				
			||||||
    args.handle();
 | 
					    args.handle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let file = args.get_file();
 | 
					    let file = args.get_file();
 | 
				
			||||||
    let contents = fs::read_to_string(&file).expect("Couldn't read the file");
 | 
					    let content = fs::read_to_string(&file).expect("Couldn't read the file");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut lexer = Lexer::new(&file, contents.as_str());
 | 
					    let mut lexer = Lexer::new(content.as_str());
 | 
				
			||||||
    let tokens = lexer.lex();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    println!("{:?}", tokens);
 | 
					    while lexer.peek_token().kind != TokenKind::Eof {
 | 
				
			||||||
 | 
					        println!("{:?}", lexer.next_token());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user