()
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | // --- Argument parsing --- |
| 124 | |
| 125 | fn parse_args() -> Result<Args, CliError> { |
| 126 | let raw: Vec<String> = std::env::args().skip(1).collect(); |
| 127 | let mut iter = raw.iter(); |
| 128 | |
| 129 | let subcmd = match iter.next().map(|s| s.as_str()) { |
| 130 | Some("link") => Subcommand::Link, |
| 131 | Some("build") => Subcommand::Build, |
| 132 | Some("hll-to-ir") => Subcommand::HllToIr, |
| 133 | Some("hll-to-asm") => Subcommand::HllToAsm, |
| 134 | Some("run") => Subcommand::Run, |
| 135 | Some("help" | "--help" | "-h") | None => Subcommand::Help, |
| 136 | Some(other) => { |
| 137 | return Err(CliError::Usage(format!( |
| 138 | "unknown subcommand `{other}`\n\nRun `fsc help` for usage." |
| 139 | ))); |
| 140 | } |
| 141 | }; |
| 142 | |
| 143 | let mut inputs: Vec<String> = Vec::new(); |
| 144 | let mut output: Option<String> = None; |
| 145 | let mut mode = TargetMode::Hosted; |
| 146 | let mut max_steps = 50_000_000u64; |
| 147 | let mut emit_object = false; |
| 148 | |
| 149 | while let Some(arg) = iter.next() { |
| 150 | match arg.as_str() { |
| 151 | "--output" | "-o" => { |
| 152 | let path = iter |
| 153 | .next() |
| 154 | .ok_or_else(|| CliError::Usage("--output requires a file path".to_owned()))?; |
| 155 | output = Some(path.clone()); |
| 156 | } |
| 157 | "--mode" | "-m" => { |
| 158 | let val = iter.next().ok_or_else(|| { |
| 159 | CliError::Usage("--mode requires `hosted` or `freestanding`".to_owned()) |
| 160 | })?; |
| 161 | mode = parse_mode(val.as_str())?; |
| 162 | } |
| 163 | "--max-steps" => { |
| 164 | let val = iter.next().ok_or_else(|| { |
| 165 | CliError::Usage("--max-steps requires a positive integer".to_owned()) |
| 166 | })?; |
| 167 | max_steps = val |
| 168 | .parse::<u64>() |
| 169 | .map_err(|_| CliError::Usage(format!("`{val}` is not a valid step count")))?; |
| 170 | } |
| 171 | "--emit-o" => { |
| 172 | emit_object = true; |
| 173 | } |
| 174 | other if !other.starts_with('-') => { |
| 175 | inputs.push(other.to_owned()); |
| 176 | } |
| 177 | other => { |
| 178 | return Err(CliError::Usage(format!( |
no test coverage detected