]> rethought.computer Git - sorel-lang.git/commitdiff
cargo fmt and a big parser cleanup
authorBryan English <bryan@rethought.computer>
Sun, 23 Aug 2026 05:54:06 +0000 (01:54 -0400)
committerBryan English <bryan@rethought.computer>
Sun, 23 Aug 2026 05:54:44 +0000 (01:54 -0400)
sorel-codegen/src/riscv64_asm.rs
sorel-ir/src/ir.rs
sorel-ir/src/lib.rs
sorel-ir/src/module.rs
sorel-parser/src/lib.rs
sorel-tokenizer/src/lib.rs
sorelc/src/import_tree.rs
sorelc/src/main.rs

index b2763662558b4fbffbac8f95313972f7dedce31f..bc8fde60d9f03b556e51d588914700e8edccada5 100644 (file)
@@ -11,13 +11,12 @@ pub struct CodeGen<'a> {
     lines: Vec<String>,
 }
 
-
 // Some inspiration
 // ================
 //
 // * https://github.com/aw/fiveforths/blob/master/docs/REFERENCE.md#registers-list
 //     * Except using sp as a more C ABI style stack pointer, and s2 for the data stack
-// 
+//
 
 // Implementation Choices
 // ======================
@@ -27,7 +26,6 @@ pub struct CodeGen<'a> {
 // Use t0, t1, t2 for temporary values in words
 // Data stack grows down
 
-
 macro_rules! asm_macro {
     ($name:ident, $src:expr) => {
         fn $name(&mut self) {
@@ -64,7 +62,6 @@ impl<'a> CodeGen<'a> {
 
     fn line<S: Display>(&mut self, line: S) {
         self.lines.push(format!("    {}", line));
-
     }
 
     fn label<S: Display>(&mut self, line: S) {
@@ -104,7 +101,7 @@ impl<'a> CodeGen<'a> {
         self.push_from(reg);
     }
 
-    pub fn assembly(&mut self) -> Result<String>{
+    pub fn assembly(&mut self) -> Result<String> {
         let mut string_table = HashMap::new();
 
         // Static strings
@@ -117,8 +114,8 @@ impl<'a> CodeGen<'a> {
                     self.label(format!("{}:", string_label));
                     self.line(format!(".asciz \"{}\"", some_string)); // should this be .asciz?
                     self.label("");
-                },
-                _ => bail!("Currently only string definitions are supported in the data section.")
+                }
+                _ => bail!("Currently only string definitions are supported in the data section."),
             }
         }
 
@@ -153,24 +150,24 @@ impl<'a> CodeGen<'a> {
                     }
 
                     self.line("addi sp, sp, -16 # allocate 16 bytes on stack"); // allocate 16 bytes on stack
-                    self.line("sd ra, 8(sp) # store return address on stack");   // store return address on stack
-                },
+                    self.line("sd ra, 8(sp) # store return address on stack"); // store return address on stack
+                }
                 IR::Call(name) => {
                     let mangled = mangle(name);
                     self.label(format!("# call {}", mangled));
-                    self.line(format!("call {}", mangled));    
-                },
+                    self.line(format!("call {}", mangled));
+                }
                 IR::WordPointer(name) => {
                     let mangled = mangle(name);
                     self.label(format!("# '{} (word pointer)", mangled));
                     self.line(format!("la t0, {}", mangled));
                     self.push_from("t0");
-                },
+                }
                 IR::CallPtr => {
                     self.label("# callptr");
                     self.pop_to("t0");
                     self.line("jalr t0");
-                },
+                }
                 IR::Ret => {
                     if last_label == "main" {
                         self.label("# exit 0 syscall");
@@ -178,104 +175,108 @@ impl<'a> CodeGen<'a> {
                         self.line("mv a0, x0");
                         self.line("ecall");
                     } else {
-                        self.line("ld ra, 8(sp)");  // load return address from stack
+                        self.line("ld ra, 8(sp)"); // load return address from stack
                         self.line("addi sp, sp, 16"); // restore stack pointer
                         self.line("ret");
                     }
-                },
+                }
                 IR::VarDecl(name) => {
                     var_decls.push(name);
-                },
+                }
                 IR::StackPushVar(name) => {
                     self.label(format!("# stackpushvar {}", name));
                     self.line(format!("la t0, {}", name));
                     self.push_from("t0");
-                },
+                }
                 IR::Load8 => {
                     self.label("# load 8");
                     self.copy_top_stack_value_to("t0");
                     self.line("lbu   t0, 0(t0)"); // deref pointer in t0 to t0
                     self.copy_to_top_of_stack("t0");
-                },
+                }
                 IR::Load16 => {
                     self.label("# load 16");
                     self.copy_top_stack_value_to("t0");
                     self.line("lhu   t0, 0(t0)"); // deref pointer in t0 to t0
                     self.copy_to_top_of_stack("t0");
-                },
+                }
                 IR::Load32 => {
                     self.label("# load 32");
                     self.copy_top_stack_value_to("t0");
                     self.line("lwu   t0, 0(t0)"); // deref pointer in t0 to t0
                     self.copy_to_top_of_stack("t0");
-                },
+                }
                 IR::Load => {
                     self.label("# load 64");
                     self.copy_top_stack_value_to("t0");
                     self.line("ld   t0, 0(t0)"); // deref pointer in t0 to t0
                     self.copy_to_top_of_stack("t0");
-                },
-                IR::Store8 => { // ( x addr -- )
+                }
+                IR::Store8 => {
+                    // ( x addr -- )
                     self.label("# store 8");
                     self.pop_some_to("t0 t1");
                     self.line("sb t0, 0(t1)"); // store x at addr 
-                },
-                IR::Store16 => { // ( x addr -- )
+                }
+                IR::Store16 => {
+                    // ( x addr -- )
                     self.label("# store 16");
                     self.pop_some_to("t0 t1");
                     self.line("sh t0, 0(t1)"); // store x at addr 
-                },
-                IR::Store32 => { // ( x addr -- )
+                }
+                IR::Store32 => {
+                    // ( x addr -- )
                     self.label("# store 32");
                     self.pop_some_to("t0 t1");
                     self.line("sw t0, 0(t1)"); // store x at addr 
-                },
-                IR::Store => { // ( x addr -- )
+                }
+                IR::Store => {
+                    // ( x addr -- )
                     self.label("# store 64");
                     self.pop_some_to("t0 t1");
                     self.line("sd t0, 0(t1)"); // store x at addr 
-                },
+                }
                 IR::StackPush(num) => {
                     self.label(format!("# stackpush {}", num));
                     self.line(format!("li t0, {}", num));
                     self.push_from("t0");
-                },
+                }
                 IR::StackPushString(name) => {
                     self.label(format!("# stackpushstring {}", name));
                     self.line(format!("la t0, {}", name));
                     self.push_from("t0");
-                },
+                }
                 IR::AddU64 => {
                     self.label("# add");
-                    self.pop_call_push("t0 t1", "add t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "add t0, t0, t1", "t0");
+                }
                 IR::SubtractU64 => {
                     self.label("# sub");
-                    self.pop_call_push("t0 t1", "sub t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "sub t0, t0, t1", "t0");
+                }
                 IR::MultiplyU64 => {
                     self.label("# multiply");
-                    self.pop_call_push("t0 t1", "mul t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "mul t0, t0, t1", "t0");
+                }
                 IR::DivideU64 => {
                     self.label("# divide");
-                    self.pop_call_push("t0 t1", "div t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "div t0, t0, t1", "t0");
+                }
                 IR::ModU64 => {
                     self.label("# mod");
-                    self.pop_call_push("t0 t1", "rem t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "rem t0, t0, t1", "t0");
+                }
                 IR::Dup => {
                     self.label("# dup");
                     self.copy_top_stack_value_to("t0");
                     self.push_from("t0");
-                },
+                }
                 IR::Swap => {
                     self.label("# swap");
                     self.pop_some_to("t1 t0");
                     self.push_from("t0");
                     self.push_from("t1");
-                },
+                }
                 IR::Over => {
                     // TODO this is super inefficient. There's no need to pop anything. Just read
                     // from the second stack position and push it.
@@ -284,19 +285,19 @@ impl<'a> CodeGen<'a> {
                     self.push_from("t0");
                     self.push_from("t1");
                     self.push_from("t0");
-                },
+                }
                 IR::Rot => {
                     self.label("# rot");
                     self.pop_some_to("t0 t1 t2");
                     self.push_from("t1");
                     self.push_from("t2");
                     self.push_from("t0");
-                },
+                }
                 IR::StackPointer => {
                     self.label("# sp");
                     self.line("addi t0, s2, 0");
                     self.push_from("t0");
-                },
+                }
                 IR::StackBottom => {
                     self.label("# stackbottom");
                     self.line("la t0, data_stack_end");
@@ -305,59 +306,59 @@ impl<'a> CodeGen<'a> {
                 IR::Drop => {
                     self.label("# drop");
                     self.move_stack_ptr_by_cells(1);
-                },
+                }
                 IR::Equals => {
                     self.label("# equals");
                     // Yes, this is the same as subtract, since we're treating 0 as true, and
                     // others as false.
-                    self.pop_call_push("t0 t1", "sub t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "sub t0, t0, t1", "t0");
+                }
                 IR::GreaterThan => {
                     self.label("# >");
                     self.pop_some_to("t0 t1");
                     self.line("sgt  t0, t0, t1");
                     self.line("seqz t0, t0"); // remember, 0 is true, others are false
                     self.push_from("t0");
-                },
+                }
                 IR::LessThan => {
                     self.label("# <");
                     self.pop_some_to("t0 t1");
                     self.line("slt  t0, t0, t1");
                     self.line("seqz t0, t0"); // remember, 0 is true, others are false
                     self.push_from("t0");
-                },
+                }
                 IR::BitwiseOr => {
                     self.label("# |");
-                    self.pop_call_push("t0 t1", "or t0, t0, t1", "t0"); 
-                },
+                    self.pop_call_push("t0 t1", "or t0, t0, t1", "t0");
+                }
                 IR::Sys0 => {
                     self.label("# syscall 0 args");
                     self.pop_call_push("a7", "ecall", "a0");
-                },
+                }
                 IR::Sys1 => {
                     self.label("# syscall 1 arg");
                     self.pop_call_push("a0 a7", "ecall", "a0");
-                },
+                }
                 IR::Sys2 => {
                     self.label("# syscall 2 args");
                     self.pop_call_push("a0 a1 a7", "ecall", "a0");
-                },
+                }
                 IR::Sys3 => {
                     self.label("# syscall 3 args");
                     self.pop_call_push("a0 a1 a2 a7", "ecall", "a0");
-                },
+                }
                 IR::Sys4 => {
                     self.label("# syscall 4 args");
                     self.pop_call_push("a0 a1 a2 a3 a7", "ecall", "a0");
-                },
+                }
                 IR::Sys5 => {
                     self.label("# syscall 5 args");
                     self.pop_call_push("a0 a1 a2 a3 a4 a7", "ecall", "a0");
-                },
+                }
                 IR::Sys6 => {
                     self.label("# syscall 6 args");
                     self.pop_call_push("a0 a1 a2 a3 a4 a5 a7", "ecall", "a0");
-                },
+                }
                 // https://cmput229.github.io/229-labs-RISCV/RISC-V-Examples_Public/03-Conditionals/03b-If_Else.html
                 IR::If => {
                     self.label("# if");
@@ -365,14 +366,14 @@ impl<'a> CodeGen<'a> {
                     self.line(format!("bnez t0, _else_{}", if_block_count));
                     if_stack.push(if_block_count);
                     if_block_count += 1;
-                },
+                }
                 IR::Else => {
                     self.label("# else");
                     let if_counter = *if_stack.last().unwrap();
                     self.line(format!("j _endif_{}", if_counter));
                     self.label(format!("_else_{}:", if_counter));
                     seen_else.insert(if_counter);
-                },
+                }
                 IR::EndIf => {
                     self.label("# endif");
                     let stack = &mut if_stack;
@@ -384,21 +385,22 @@ impl<'a> CodeGen<'a> {
                         seen_else.remove(&if_counter);
                     }
                     stack.pop();
-                },
-                IR::Loop => { // keep looping until is true/0
+                }
+                IR::Loop => {
+                    // keep looping until is true/0
                     self.label(format!("_loop_{}:", loop_count));
                     self.pop_to("t0");
                     self.line(format!("beqz t0, _endloop_{}", loop_count));
                     loop_stack.push(loop_count);
                     loop_count += 1;
-                },
+                }
                 IR::EndLoop => {
                     let stack = &mut loop_stack;
                     let loop_counter = *stack.last().unwrap();
                     self.line(format!("j _loop_{}", loop_counter));
                     self.label(format!("_endloop_{}:", loop_counter));
                     stack.pop();
-                },
+                }
                 _ => bail!("not implemented yet: {:?}", ir),
             }
         }
@@ -417,4 +419,3 @@ impl<'a> CodeGen<'a> {
         Ok(self.lines.join("\n"))
     }
 }
-
index aa2dde053e52e595e8d2591b89be68f8a534fd52..3396df37cbb0fbbc2a0ebfa0129facd8fe6d83f5 100644 (file)
@@ -59,8 +59,12 @@ pub enum IR {
 }
 
 macro_rules! push_num {
-    ($num:ident) => { IR::StackPush(*$num as u64) };
-    ($num:ident, $num_typ:ty) => { IR::StackPush(*$num as $num_typ as u64) };
+    ($num:ident) => {
+        IR::StackPush(*$num as u64)
+    };
+    ($num:ident, $num_typ:ty) => {
+        IR::StackPush(*$num as $num_typ as u64)
+    };
 }
 
 impl IR {
@@ -106,7 +110,7 @@ impl IR {
                     "sys5" => IR::Sys5,
                     "sys6" => IR::Sys6,
                     // TODO num type specfic math like `+:i32`, etc.
-                    _ =>  {
+                    _ => {
                         if let Some(actual_word) = word.strip_prefix("'") {
                             IR::WordPointer(String::from(actual_word))
                         } else {
@@ -114,12 +118,12 @@ impl IR {
                         }
                     }
                 }
-            },
+            }
             Token::String(text) => {
                 let string_label = format!("string_{}", data.len());
                 data.push(IR::StringDef(string_label.clone(), String::from(*text)));
                 IR::StackPushString(string_label)
-            },
+            }
             Token::NumU8(num) => push_num!(num),
             Token::NumI8(num) => push_num!(num, u8),
             Token::NumU16(num) => push_num!(num),
@@ -131,5 +135,5 @@ impl IR {
             Token::NumF32(num) => push_num!(num),
             Token::NumF64(num) => push_num!(num),
         }
-    } 
+    }
 }
index f27c139908765857e7b302fabbfdd0b457f765d7..c15f58d5976de1105d406f442db38055450b3514 100644 (file)
@@ -6,4 +6,3 @@ pub use object::*;
 
 mod module;
 pub use module::*;
-
index f5591772c9f460fc48a16edd017c0ab9cb5d30a9..f45559932304a7e70d3abe1a86be4b11053552bf 100644 (file)
@@ -1,6 +1,6 @@
-use std::rc::Rc;
 use std::cell::RefCell;
 use std::path::PathBuf;
+use std::rc::Rc;
 
 use crate::ir::IR;
 
@@ -9,7 +9,7 @@ pub type WrappedIRModule = Rc<RefCell<IRModule>>;
 #[derive(Debug, PartialEq, Clone)]
 pub enum ModuleID {
     SourceFile(PathBuf),
-    StdSpecifier(String)
+    StdSpecifier(String),
 }
 
 impl Default for ModuleID {
@@ -22,7 +22,7 @@ impl ModuleID {
     pub fn to_string(&self) -> String {
         match self {
             ModuleID::SourceFile(f) => f.to_string_lossy().to_string(),
-            ModuleID::StdSpecifier(s) => s.clone()
+            ModuleID::StdSpecifier(s) => s.clone(),
         }
     }
 }
@@ -50,7 +50,7 @@ impl IRModule {
             if imported.exports.contains(name) {
                 found = Some(imported.number);
                 // Don't break here, since the last one should win.
-            }            
+            }
         }
         if let Some(found) = found {
             format!("_m{}_{}", found, name)
index 120243ffb747f52a7a1654b10903df470062a598..e269e062858e039ce3f11dd0fb63d7044b26a171 100644 (file)
@@ -1,5 +1,5 @@
+use anyhow::{Result, anyhow, bail};
 use sorel_tokenizer::Token;
-use anyhow::{Result, bail};
 
 #[derive(Debug)]
 pub struct WordDefinition<'a> {
@@ -7,7 +7,7 @@ pub struct WordDefinition<'a> {
     pub instructions: Vec<Token<'a>>,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct Module<'a> {
     pub words: Vec<WordDefinition<'a>>,
     pub imports: Vec<&'a str>,
@@ -15,97 +15,102 @@ pub struct Module<'a> {
     pub externs: Vec<&'a str>,
 }
 
+enum LastMeta {
+    Import,
+    Export,
+    Extern,
+    None,
+}
+
 impl<'a> Module<'a> {
     pub fn parse(input: Vec<Token<'a>>, is_entrypoint: bool) -> Result<Self> {
-        let mut result = vec![];
+        let mut module = Module::default();
         let mut main = vec![];
-        let mut exports = vec![];
-        let mut imports = vec![];
-        let mut externs = vec![];
         let mut current_word: Option<WordDefinition> = None;
-        let mut about_to_start_word_def = false;
-        let mut last_was_import = false;
-        let mut last_was_export = false;
-        let mut last_was_extern = false;
+        let mut last_was_colon = false;
+        let mut last_meta = LastMeta::None;
 
         for token in input {
-            if about_to_start_word_def {
-                if let Token::Word(name) = token {
-                    current_word = Some(WordDefinition {
-                        name,
-                        instructions: vec![],
-                    });
-                    about_to_start_word_def = false;
-                    continue;
-                } else {
-                    bail!("{:?} is not a valid word name!", token);
-                }
-            } else if let Token::Word(word) = token {
+            if last_was_colon {
+                // We're about to start defining a word, and the current token
+                // is the word's name.
+                current_word = Some(WordDefinition {
+                    name: token.as_word()?,
+                    instructions: vec![],
+                });
+                last_was_colon = false;
+                continue;
+            }
+
+            if let Token::Word(word) = token {
                 if word == ":" {
                     if current_word.is_some() {
                         bail!("can't define words inside word definitions!");
                     }
-                    about_to_start_word_def = true;
+                    last_was_colon = true;
                     continue;
                 }
                 if word == ";" {
-                    let word = current_word.take();
-                    if let Some(word) = word {
-                        result.push(word);
-                        continue;
-                    } else {
-                        bail!("`;` must be at the end of a word definition");
-                    }
+                    let word = current_word
+                        .take()
+                        .expect("`;` must be at the end of a word definition");
+                    module.words.push(word);
+                    continue;
                 }
             }
+
             if let Some(ref mut current_word) = current_word {
                 current_word.instructions.push(token);
-            } else {
-                match token {
-                    Token::Word(word) => {
-                        if word == "import" {
-                            last_was_import = true;
-                        } else if word == "export" {
-                            last_was_export = true;
-                        } else if word == "extern" {
-                            last_was_extern = true;
-                        } else if last_was_export {
-                            exports.push(word);
-                            last_was_export = false;
-                        } else if last_was_extern {
-                            externs.push(word);
-                            last_was_extern = false;
-                        } else {
-                            main.push(token.clone());
-                        }
-                    },
-                    Token::String(string) => {
-                        if last_was_import {
-                            imports.push(string);
-                            last_was_import = false;
-                        } else {
-                            main.push(token.clone());
-                        }
-                    },
-                    _ => {
-                        main.push(token.clone());
-                    }
-                };
+                continue;
+            }
+
+            // From here on out, we're at the top level in the module, which
+            // means either a "meta" (import, export, or extern) or raw code
+            // to be added to the `main` word if we're in the entrypoint, or
+            // ignored otherwise. This macro makes the code a little tighter.
+
+            macro_rules! push_token {
+                ($as_type:ident, $coll:ident, $bail1:expr, $bail2:expr) => {{
+                    let token = token
+                        .$as_type()
+                        .map_err(|_| anyhow!("`${}` must be followed by a ${}", $bail1, $bail2))?;
+                    module.$coll.push(token);
+                    LastMeta::None
+                }};
+                () => {{
+                    main.push(token);
+                    LastMeta::None
+                }};
             }
+
+            last_meta = match last_meta {
+                LastMeta::Import => push_token!(as_string, imports, "import", "string"),
+                LastMeta::Export => push_token!(as_word, exports, "export", "word"),
+                LastMeta::Extern => push_token!(as_word, externs, "extern", "word"),
+                LastMeta::None => match token {
+                    Token::Word(word) => match word {
+                        "import" => LastMeta::Import,
+                        "export" => LastMeta::Export,
+                        "extern" => LastMeta::Extern,
+                        _ => push_token!(),
+                    },
+                    _ => push_token!(),
+                },
+            };
         }
 
-        if about_to_start_word_def || current_word.is_some() {
+        if last_was_colon || current_word.is_some() {
             bail!("unfinished word definition!");
         }
 
         if is_entrypoint {
-            result.push(WordDefinition {
+            module.words.push(WordDefinition {
                 name: "main",
                 instructions: main,
             });
         }
-        
-        Ok(Module { words: result, imports, exports, externs })
+
+        Ok(module)
     }
 
     #[cfg(test)]
@@ -119,20 +124,25 @@ impl<'a> Module<'a> {
     }
 }
 
-
-
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
     fn try_some_parsing() {
-        let result = Module::parse(sorel_tokenizer::tokenize("
+        let result = Module::parse(
+            sorel_tokenizer::tokenize(
+                "
 : hello world 16 \"planet\" ;
 : soup chicken 4.5 hello ;
 
 hello soup
-").unwrap(), true).unwrap();
+",
+            )
+            .unwrap(),
+            true,
+        )
+        .unwrap();
         result.debug_print();
     }
 }
index 86c2b42e9a43e707f3d5bf6460311334c5b826ac..417fce186816713194fbef0fbe3b2fb8ac78bca7 100644 (file)
@@ -1,4 +1,4 @@
-use anyhow::{Result, anyhow};
+use anyhow::{Result, anyhow, bail};
 use std::str::FromStr;
 
 #[derive(Debug, Clone)]
@@ -18,7 +18,9 @@ pub enum Token<'a> {
 }
 
 trait IntFromStrRadix {
-    fn from_radix(src: &str, radix: u32) -> Result<Self> where Self: Sized;
+    fn from_radix(src: &str, radix: u32) -> Result<Self>
+    where
+        Self: Sized;
 }
 
 macro_rules! radix_impl {
@@ -49,18 +51,41 @@ fn parse_int<T: IntFromStrRadix + FromStr>(num: &str) -> Result<T> {
 }
 
 fn parse_float<T: FromStr>(num: &str) -> Result<T> {
-    num.parse().map_err(|_| anyhow!("parse error for number: {}", num))
+    num.parse()
+        .map_err(|_| anyhow!("parse error for number: {}", num))
 }
 
-impl<'a> Token<'a>{
+impl<'a> Token<'a> {
+    pub fn as_word(&self) -> Result<&'a str> {
+        if let Token::Word(string) = self {
+            Ok(string)
+        } else {
+            bail!("{:?} is not a valid word name!", self);
+        }
+    }
+
+    pub fn as_string(&self) -> Result<&'a str> {
+        if let Token::String(string) = self {
+            Ok(string)
+        } else {
+            bail!("{:?} is not a valid string!", self);
+        }
+    }
+
     fn parse_word_or_num(input: &'a str) -> Result<Token<'a>> {
         if input == "-" {
-            return Ok(Token::Word(input))
+            return Ok(Token::Word(input));
         }
-        
+
         // we're assuming any token starting with `-` with length greater than one
         // is a negative number
-        if input.starts_with('-') || input.chars().nth(0).map(|x| x.is_numeric()).unwrap_or(false) {
+        if input.starts_with('-')
+            || input
+                .chars()
+                .nth(0)
+                .map(|x| x.is_numeric())
+                .unwrap_or(false)
+        {
             if input.contains(':') {
                 let mut splat = input.split(':');
                 let num = splat.next().ok_or(anyhow!("no number found"))?;
@@ -76,7 +101,7 @@ impl<'a> Token<'a>{
                     "i64" => Ok(Token::NumI64(parse_int(num)?)),
                     "f32" => Ok(Token::NumF32(parse_float(num)?)),
                     "f64" => Ok(Token::NumF64(parse_float(num)?)),
-                    _ => panic!("unknown number type")
+                    _ => panic!("unknown number type"),
                 }
             } else if input.contains('.') {
                 Ok(Token::NumF64(parse_float(input)?))
@@ -103,14 +128,13 @@ pub fn tokenize<'a>(input: &'a str) -> Result<Vec<Token<'a>>> {
     let mut index = 0;
     let mut first_char = true;
 
-
     for char in input.chars() {
         if first_char {
             first_char = false;
         } else {
             index += 1;
         }
-        
+
         if in_doc_comment {
             if char == ')' {
                 in_doc_comment = false;
@@ -135,14 +159,13 @@ pub fn tokenize<'a>(input: &'a str) -> Result<Vec<Token<'a>>> {
                     string_start = None;
                 }
             } else {
-                string_start = Some(index + 1)                
+                string_start = Some(index + 1)
             }
             last_is_backslash = false;
             last_is_whitespace = false;
             continue;
         }
 
-
         if string_start.is_some() {
             last_is_backslash = char == '\\';
             continue;
@@ -150,7 +173,7 @@ pub fn tokenize<'a>(input: &'a str) -> Result<Vec<Token<'a>>> {
 
         if char.is_whitespace() {
             if last_is_backslash {
-                in_line_comment = true;                
+                in_line_comment = true;
             } else if !last_is_whitespace && let Some(start) = word_or_num_start {
                 let token = &input[start..index];
                 if token == "(" {
@@ -174,7 +197,8 @@ pub fn tokenize<'a>(input: &'a str) -> Result<Vec<Token<'a>>> {
             continue;
         }
 
-        if last_is_whitespace { // start of word or num (we already handled strings)
+        if last_is_whitespace {
+            // start of word or num (we already handled strings)
             word_or_num_start = Some(index);
             last_is_whitespace = false;
         }
@@ -188,17 +212,20 @@ mod tests {
 
     #[test]
     fn try_some_tokenizing() {
-        let result = tokenize("
+        let result = tokenize(
+            "
 
         \\ soup
             2 0x10 3.4 - -88 bacon \"hello\" 43:f32 2345:u32 -57:i8 soup
-");
+",
+        );
         println!("result: {:?}", result);
     }
 
     #[test]
     fn comments() {
-        let result = tokenize("
+        let result = tokenize(
+            "
             (
                 foo
                 bar
@@ -207,16 +234,19 @@ mod tests {
               chicken
               soup
             ;
-        ");
+        ",
+        );
         println!("result: {:?}", result);
     }
 
     #[test]
     fn strings() {
-        let result = tokenize("
+        let result = tokenize(
+            "
 dup \\ ( stuff )
 \"hello!\"
-");
+",
+        );
         println!("result: {:?}", result);
     }
 }
index 6ac87d1c271d7eefe44f44223448bda845923a17..2d88abf9465bdb246e77f6a857256997ee231fd5 100644 (file)
@@ -1,14 +1,14 @@
-use sorel_parser::Module;
 use sorel_ir::*;
+use sorel_parser::Module;
 use sorel_tokenizer::tokenize;
 
-use std::collections::{HashSet, HashMap};
-use std::path::PathBuf;
-use std::rc::Rc;
 use std::cell::RefCell;
+use std::collections::{HashMap, HashSet};
 use std::include_str;
+use std::path::PathBuf;
+use std::rc::Rc;
 
-use anyhow::{Result, bail, anyhow};
+use anyhow::{Result, anyhow, bail};
 
 #[derive(Default)]
 pub(crate) struct ImportTree {
@@ -32,14 +32,22 @@ fn std_import(specifier: &str) -> Result<&str> {
 }
 
 impl ImportTree {
-    fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result<WrappedIRModule> {
+    fn import(
+        &mut self,
+        importer_dir: &PathBuf,
+        specifier: &str,
+        is_entrypoint: bool,
+    ) -> Result<WrappedIRModule> {
         let (contents, module_id) = if specifier.starts_with("std:") {
             if self.all_modules.contains_key(specifier) {
                 let module = self.all_modules.get(specifier).unwrap().clone();
                 return Ok(module);
             }
             let contents = std_import(specifier)?;
-            (contents.to_string(), ModuleID::StdSpecifier(specifier.to_string()))
+            (
+                contents.to_string(),
+                ModuleID::StdSpecifier(specifier.to_string()),
+            )
         } else {
             let mut path = PathBuf::from(specifier);
             if path.is_relative() {
@@ -60,7 +68,8 @@ impl ImportTree {
         let parsed = &Module::parse(tokens, is_entrypoint)?;
         let module = self.ir_mod_from_parsed(module_id.clone(), parsed)?;
         let module = Rc::new(RefCell::new(module));
-        self.all_modules.insert(module_id.to_string(), module.clone());
+        self.all_modules
+            .insert(module_id.to_string(), module.clone());
         if is_entrypoint {
             self.entrypoint = module.clone();
         }
@@ -75,65 +84,76 @@ impl ImportTree {
         let mut imports = vec![];
 
         let parent_path = match module_id {
-            ModuleID::SourceFile(ref path) => {
-                path.parent().ok_or(anyhow!("no parent for path: {:?}", path))?.to_path_buf()
-            },
+            ModuleID::SourceFile(ref path) => path
+                .parent()
+                .ok_or(anyhow!("no parent for path: {:?}", path))?
+                .to_path_buf(),
             // A stdlib module can only import other stdlib
             // modules, so no need for parent path.
             ModuleID::StdSpecifier(_) => PathBuf::new(),
         };
-        module.imports.iter().try_for_each(|imported| -> Result<()> {
-            let new_module = self.import(&parent_path, imported, false)?;
-            imports.push(new_module);
-            Ok(())
-        })?;
+        module
+            .imports
+            .iter()
+            .try_for_each(|imported| -> Result<()> {
+                let new_module = self.import(&parent_path, imported, false)?;
+                imports.push(new_module);
+                Ok(())
+            })?;
 
-        let exports: Vec<_> = module.exports.iter().map(|s| {
-            self.all_exports.insert(s.to_string());
-            s.to_string()
-        }).collect();
+        let exports: Vec<_> = module
+            .exports
+            .iter()
+            .map(|s| {
+                self.all_exports.insert(s.to_string());
+                s.to_string()
+            })
+            .collect();
 
         let externs = module.externs.iter().map(|s| s.to_string()).collect();
 
-        module.words.iter().try_for_each(|def| -> Result<(), anyhow::Error> {
-            let mut body = vec![];
-            let mut last_call_was_var = false;
-            let mut vars = vec![];
-            def.instructions.iter().try_for_each(|inst| {
-                let new_token = IR::from_token(inst, &mut data);
-                if let IR::Call(thing) = new_token {
-                    if thing == "var" {
-                        last_call_was_var = true;
-                    } else {
-                        if last_call_was_var {
-                            body.push(IR::VarDecl(thing.clone()));
-                            vars.push(thing);
-                            last_call_was_var = false;
+        module
+            .words
+            .iter()
+            .try_for_each(|def| -> Result<(), anyhow::Error> {
+                let mut body = vec![];
+                let mut last_call_was_var = false;
+                let mut vars = vec![];
+                def.instructions.iter().try_for_each(|inst| {
+                    let new_token = IR::from_token(inst, &mut data);
+                    if let IR::Call(thing) = new_token {
+                        if thing == "var" {
+                            last_call_was_var = true;
                         } else {
-                            if vars.contains(&thing) {
-                                body.push(IR::StackPushVar(thing));
+                            if last_call_was_var {
+                                body.push(IR::VarDecl(thing.clone()));
+                                vars.push(thing);
+                                last_call_was_var = false;
                             } else {
-                                body.push(IR::Call(thing));
+                                if vars.contains(&thing) {
+                                    body.push(IR::StackPushVar(thing));
+                                } else {
+                                    body.push(IR::Call(thing));
+                                }
                             }
                         }
-                    }
-                } else {
-                    if last_call_was_var {
-                        bail!("word must come after var!")
                     } else {
-                        body.push(new_token);
+                        if last_call_was_var {
+                            bail!("word must come after var!")
+                        } else {
+                            body.push(new_token);
+                        }
                     }
-                }
+                    Ok(())
+                })?;
+
+                let mut result = vec![IR::Label(def.name.to_string())];
+                result.append(&mut body);
+                result.push(IR::Ret);
+                text.push(result);
                 Ok(())
             })?;
 
-            let mut result = vec![IR::Label(def.name.to_string())];
-            result.append(&mut body);
-            result.push(IR::Ret);
-            text.push(result);
-            Ok(())
-        })?;
-
         let number = self.module_count;
         self.module_count += 1;
 
@@ -152,7 +172,7 @@ impl ImportTree {
         let module = module.borrow_mut();
         let seen_key = module.module_id.to_string();
         if self.collapse_seen.contains(&seen_key) {
-            return Ok(())
+            return Ok(());
         }
 
         for imported in module.imports.clone() {
@@ -176,7 +196,7 @@ impl ImportTree {
                 IR::StackPushString(name) => {
                     let new_name = format!("{}_{}", name, module_number);
                     IR::StackPushString(new_name)
-                },
+                }
                 IR::Label(name) => {
                     if is_entrypoint && name == "main" {
                         last_label_name = String::from("main");
@@ -186,20 +206,14 @@ impl ImportTree {
                         last_label_name = label_name.clone();
                         IR::Label(module.get_label(name))
                     }
-                },
-                IR::VarDecl(name) => {
-                    IR::VarDecl(format!("_var_{}_{}", last_label_name, name))
-                },
+                }
+                IR::VarDecl(name) => IR::VarDecl(format!("_var_{}_{}", last_label_name, name)),
                 IR::StackPushVar(name) => {
                     IR::StackPushVar(format!("_var_{}_{}", last_label_name, name))
-                },
-                IR::Call(name) => {
-                    IR::Call(module.get_label_for_call(name))
-                },
-                IR::WordPointer(name) => {
-                    IR::WordPointer(module.get_label_for_call(name))
-                },
-                _ => instruction.clone()
+                }
+                IR::Call(name) => IR::Call(module.get_label_for_call(name)),
+                IR::WordPointer(name) => IR::WordPointer(module.get_label_for_call(name)),
+                _ => instruction.clone(),
             };
             self.text.push(new_instruction);
         }
@@ -212,10 +226,10 @@ impl ImportTree {
 
 pub fn build_and_collapse(path: &str) -> Result<IRObject> {
     let dir = std::env::current_dir()?;
-    let mut tree: ImportTree = Default::default(); 
+    let mut tree: ImportTree = Default::default();
     let module = tree.import(&dir, path, true)?;
     tree.collapse(module, true)?;
-    // TODO remove unused words 
+    // TODO remove unused words
     Ok(IRObject {
         data: tree.data,
         text: tree.text,
index 18c93a2084a86d414120dd82f99d96045bc07c23..4c78deab88ee69e84f3529fb747900737b9c83e8 100644 (file)
@@ -8,7 +8,9 @@ use std::io::Write;
 use std::path::PathBuf;
 
 fn main() -> Result<()> {
-    let filename = std::env::args().nth(1).expect("must provide a file to compile");
+    let filename = std::env::args()
+        .nth(1)
+        .expect("must provide a file to compile");
     let module = import_tree::build_and_collapse(&filename)?;
     let mut generator = CodeGen::new(&module, 4096);
     let mut asm_path = PathBuf::from(filename);