]> rethought.computer Git - sorel-lang.git/commitdiff
implement stdlib in import system keep/af62aae5ee593617cc71644932aff6acef3d9857
authorBryan English <bryan@rethought.computer>
Wed, 4 Feb 2026 03:04:05 +0000 (22:04 -0500)
committerBryan English <bryan@rethought.computer>
Tue, 10 Feb 2026 04:08:54 +0000 (04:08 +0000)
rel-lang/rel-interpret/src/lib.rs
rel-lang/rel-ir/src/lib.rs
rel-lang/relc/src/ir.rs
rel-lang/stdlib/mem.rel
rel-lang/stdlib/out.rel
rel-lang/stdlib/putn.c [deleted file]
rel-lang/stdlib/test.sh [deleted file]
rel-lang/tests/test.sh [new file with mode: 0644]
rel-lang/tests/test1.rel [new file with mode: 0644]

index 68fa489d00c2703ec84040e64104a361751a286e..edd6e48d70bab79822387f572c29fdd7baaf50bb 100644 (file)
@@ -102,9 +102,6 @@ impl<'a> Interpreter<'a> {
                         let a = self.ds_pop()?;
                         self.data_stack.push(a - b);
                     },
-                    IR::PutN => {
-                        println!("{}", self.data_stack.last().ok_or(anyhow!("empty data stack"))?);
-                    },
                     IR::Dup => {
                         self.data_stack.push(*self.data_stack.last().ok_or(anyhow!("empty data stack"))?);
                     },
index 699dbba189adb026ceb2dbc505148425e73d6e22..919a08fa13987dcf57c9a3c0465d4ba1470afb7f 100644 (file)
@@ -27,13 +27,14 @@ pub enum IR {
     ModU64,
     Equals,
     GreaterThan,
+    LessThan,
     BitwiseOr,
     Dup,
     Swap,
     Drop,
     Over,
     Rot,
-    PutN,
+    StackPointer,
     If,
     Else,
     EndIf,
index aa50b1819dbf5401b2dcb1ea63f2bef9d13d7dc9..55006f665c81710fe996490643748eb8a1489c03 100644 (file)
@@ -5,6 +5,7 @@ use rel_ir::*;
 use std::collections::{HashSet, HashMap};
 use std::path::PathBuf;
 use std::rc::Rc;
+use std::include_str;
 
 use anyhow::{Result, bail};
 
@@ -19,7 +20,9 @@ struct IRModule {
     text: Vec<IR>,
     imports: Vec<Rc<IRModule>>,
     exports: Vec<String>,
-    source_file: PathBuf,
+    // TODO these next two should form an enum, not two options
+    source_file: Option<PathBuf>,
+    std_specifier: Option<String>,
     number: usize,
 }
 
@@ -49,46 +52,80 @@ impl IRModule {
 struct ImportTree {
     data: Vec<IR>,
     text: Vec<IR>,
-    all_modules: HashMap<PathBuf, Rc<IRModule>>,
+    all_modules: HashMap<String, Rc<IRModule>>,
     all_exports: HashSet<String>,
     entrypoint: Rc<IRModule>,
     module_count: usize,
-    collapse_seen: HashSet<PathBuf>,
+    collapse_seen: HashSet<String>,
+}
+
+fn std_import(specifier: &str) -> Result<&str> {
+    match specifier {
+        "std:mem" => Ok(include_str!("../../stdlib/mem.rel")),
+        "std:out" => Ok(include_str!("../../stdlib/out.rel")),
+        _ => bail!("{} is not a standard library module", specifier),
+    }
 }
 
 impl ImportTree {
     fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result<Rc<IRModule>> {
-        let mut path = PathBuf::from(specifier);
-        if path.is_relative() {
-            let mut new_path = importer_dir.clone();
-            new_path.push(path);
-            path = new_path.canonicalize()?;
-        }
-        if self.all_modules.contains_key(&path) {
-            let module = self.all_modules.get(&path).unwrap().clone();
-            return Ok(module);
-        }
+        Ok(if specifier.starts_with("std:") {
+            let contents = std_import(specifier)?;
+            let parsed = &Module::parse(tokenize(&contents)?, is_entrypoint)?;
+            let module = self.generate_internal(None, Some(specifier.to_string()), parsed);
+            let module = Rc::new(module);
+            self.all_modules.insert(specifier.to_string(), module.clone());
+            module
+        } else {
+            let mut path = PathBuf::from(specifier);
+            if path.is_relative() {
+                let mut new_path = importer_dir.clone();
+                new_path.push(path);
+                path = new_path.canonicalize()?;
+            }
+            let path_key = path.to_string_lossy().to_string();
+            if self.all_modules.contains_key(&path_key) {
+                let module = self.all_modules.get(&path_key).unwrap().clone();
+                return Ok(module);
+            }
 
-        let contents = std::fs::read_to_string(&path)?;
+            let contents = &std::fs::read_to_string(&path)?;
+            let module = self.generate_internal(Some(path), None, &Module::parse(tokenize(&contents)?, is_entrypoint)?);
+            let module = Rc::new(module);
+            self.all_modules.insert(path_key, module.clone());
+            if is_entrypoint {
+                self.entrypoint = module.clone();
+            }
+            module
+        })
 
-        let module = self.generate_internal(path, &Module::parse(tokenize(&contents)?, is_entrypoint)?);
-        let module = Rc::new(module);
-        self.all_modules.insert(module.source_file.clone(), module.clone());
-        if is_entrypoint {
-            self.entrypoint = module.clone();
-        }
-        Ok(module)
     }
 
-    fn generate_internal(&mut self, path: PathBuf, module: &Module) -> IRModule {
+    fn generate_internal(&mut self, path: Option<PathBuf>, std_specifier: Option<String>, module: &Module) -> IRModule {
         // Eventually these will end up being sections in assembly
         let mut text = vec![];
         let mut data = vec![];
 
         let mut imports = vec![];
-        module.imports.iter().for_each(|imported| {
-            if let Some(parent_path) = path.parent() {
-                match self.import(&parent_path.to_path_buf(), imported, false) {
+        if let Some(ref path) = path {
+            module.imports.iter().for_each(|imported| {
+                if let Some(parent_path) = path.parent() {
+                    match self.import(&parent_path.to_path_buf(), imported, false) {
+                        Ok(module) => {
+                            imports.push(module);
+                        },
+                        Err(msg) => {
+                            eprintln!("{}", msg);
+                        }
+                    }
+                } else {
+                }
+            });
+        } else {
+            // We're in a stdlib module, which can only import other stdlib
+            // modules.
+            module.imports.iter().for_each(|imported| {
+                match self.import(&PathBuf::new(), imported, false) {
                     Ok(module) => {
                         imports.push(module);
                     },
@@ -96,9 +133,8 @@ impl ImportTree {
                         eprintln!("{}", msg);
                     }
                 }
-            } else {
-            }
-        });
+            });
+        }
         
         let exports: Vec<_> = module.exports.iter().map(|s| {
             self.all_exports.insert(s.to_string());
@@ -181,12 +217,18 @@ impl ImportTree {
             imports,
             exports,
             source_file: path,
+            std_specifier, 
             number,
         }
     }
 
     fn collapse(&mut self, module: Rc<IRModule>) -> Result<()> {
-        if self.collapse_seen.contains(&module.source_file) {
+        let seen_key = if let Some(source_file) = &module.source_file {
+            source_file.to_string_lossy().to_string()
+        } else {
+            module.std_specifier.clone().unwrap()
+        };
+        if self.collapse_seen.contains(&seen_key) {
             return Ok(())
         }
 
@@ -228,6 +270,8 @@ impl ImportTree {
             self.text.push(new_instruction);
         }
 
+        self.collapse_seen.insert(seen_key);
+
         Ok(())
     }
 }
index 49d14dbe4c4cfa29f6ca5bce8ae06ca629a17a52..da5bfca6f505be6cd869055f5e7d30bf52dd7d0b 100644 (file)
@@ -42,5 +42,3 @@ export free
   dealloc
 ; 
 
-1024 alloc
-free
index 48dfd9464b77814e8ca20c31481536862cf5cb20..000b32042160bd1387297c1a487e39d38d9dec0e 100644 (file)
@@ -17,6 +17,8 @@
   - \ ( len )
 ;
 
+export puts
+
 : puts ( addr -- addr)
   dup dup \ ( addr addr addr )
   strlen \ ( addr addr len )
@@ -27,8 +29,6 @@
   drop \ ( addr )
 ;
 
-"Hello, World! \n" puts
-
 : ZERO_CHAR 48 ;
 : NEWLINE_CHAR 10 ;
 
@@ -67,4 +67,3 @@ export putn
   drop \ ( num )
 ;
 
-28 putn
diff --git a/rel-lang/stdlib/putn.c b/rel-lang/stdlib/putn.c
deleted file mode 100644 (file)
index 201050c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <stdio.h>
-
-extern unsigned long data_stack_end;
-register unsigned long * stack_pointer asm("s2");
-
-void putn() {
-  unsigned long * stack_index = &data_stack_end;
-  printf("stack: ");
-  while (stack_index != stack_pointer) {
-         printf("%ld ", *stack_index);
-    stack_index -= 1;
-  }
-       printf("%ld\n", *stack_pointer);
-}
-
-
diff --git a/rel-lang/stdlib/test.sh b/rel-lang/stdlib/test.sh
deleted file mode 100644 (file)
index 0bef584..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-UNAME=$(uname -m)
-CMD_PREFIX=$([ "$UNAME" = "riscv64" ] && echo "" || echo "riscv64-unknown-linux-gnu-")
-AS="${CMD_PREFIX}as"
-CC="${CMD_PREFIX}cc"
-
-
-# ../target/debug/relc mem.rel
-# $AS -o mem.o mem.asm
-# $CC -O1 -no-pie -o test-mem.out putn.c mem.o -nostartfiles 
-# ./test-mem.out
-
-
-../target/debug/relc out.rel
-$AS -o out.o out.asm
-$CC -O1 -no-pie -o test-out.out out.o putn.c -nostartfiles 
-./test-out.out
diff --git a/rel-lang/tests/test.sh b/rel-lang/tests/test.sh
new file mode 100644 (file)
index 0000000..328e1e6
--- /dev/null
@@ -0,0 +1,9 @@
+UNAME=$(uname -m)
+CMD_PREFIX=$([ "$UNAME" = "riscv64" ] && echo "" || echo "riscv64-unknown-linux-gnu-")
+AS="${CMD_PREFIX}as"
+LD="${CMD_PREFIX}ld"
+
+../target/debug/relc test1.rel
+$AS -o test1.o test1.asm
+$LD -o test1.out test1.o
+./test1.out
diff --git a/rel-lang/tests/test1.rel b/rel-lang/tests/test1.rel
new file mode 100644 (file)
index 0000000..0adf96a
--- /dev/null
@@ -0,0 +1,14 @@
+\ vim: filetype=forth
+
+import "std:out"
+
+"Hello, World! \n" puts
+drop
+
+42 putn
+drop
+
+import "std:mem"
+
+64 alloc
+free