diff options
Diffstat (limited to 'crates/sloth_vm/src')
| -rw-r--r-- | crates/sloth_vm/src/native.rs | 1 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/file.rs | 83 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/misc.rs | 39 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/mod.rs | 19 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/rand.rs | 9 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/stdio.rs | 42 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/term.rs | 41 | ||||
| -rw-r--r-- | crates/sloth_vm/src/sloth_std/time.rs | 29 | 
8 files changed, 262 insertions, 1 deletions
| diff --git a/crates/sloth_vm/src/native.rs b/crates/sloth_vm/src/native.rs index 8790cbd..fbd2626 100644 --- a/crates/sloth_vm/src/native.rs +++ b/crates/sloth_vm/src/native.rs @@ -15,4 +15,5 @@ pub struct NativeFunction {      pub function: NativeFunctionInput,      pub arity: u8,      pub returns_value: bool, +    pub doc: Option<&'static str>,  } diff --git a/crates/sloth_vm/src/sloth_std/file.rs b/crates/sloth_vm/src/sloth_std/file.rs new file mode 100644 index 0000000..b0b476a --- /dev/null +++ b/crates/sloth_vm/src/sloth_std/file.rs @@ -0,0 +1,83 @@ +use std::fs; + +use crate::native::{self, NativeFunction, NativeFunctionResult}; +use crate::value::{Object, ObjectType, Primitive}; +use crate::VM; + +fn file_read(vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let Some(Primitive::Object(ptr)) = args.get(0).cloned() else { +        return Err(native::Error::InvalidArgument); +    }; + +    let object = vm +        .objects() +        .get(ptr as usize) +        .ok_or(native::Error::InvalidArgument)?; + +    let ObjectType::String(str) = &object.typ else { +        return Err(native::Error::InvalidArgument); +    }; + +    let contents = fs::read_to_string(str).expect("IO Error: Failed to read file!"); + +    let object = Object::new(ObjectType::String(contents)); +    let ptr = vm.objects_mut().allocate(object); + +    Ok(Primitive::Object(ptr as u32)) +} + +pub const FILE_READ: NativeFunction = NativeFunction { +    name: "file$read", +    function: file_read, +    arity: 1, +    returns_value: true, +    doc: Some( +        "NativeFunction file$read: \n\targs: path (str)\n\tdesc: Returns the contents of a file \ +         at <path>\n\tExample: `var todo = file$read('/home/sloth/todo.txt'); # Assuming the \ +         contents of todo.txt are 'Take a nap' then todo = 'Take a nap'`", +    ), +}; + +fn file_write(vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let Some(Primitive::Object(path_ptr)) = args.get(0).cloned() else { +        return Err(native::Error::InvalidArgument); +    }; + +    let path_object = vm +        .objects() +        .get(path_ptr as usize) +        .ok_or(native::Error::InvalidArgument)?; + +    let ObjectType::String(path) = &path_object.typ else { +        return Err(native::Error::InvalidArgument); +    }; + +    let Some(Primitive::Object(content_ptr)) = args.get(1).cloned() else { +        return Err(native::Error::InvalidArgument); +    }; + +    let content_object = vm +        .objects() +        .get(content_ptr as usize) +        .ok_or(native::Error::InvalidArgument)?; + +    let ObjectType::String(content) = &content_object.typ else { +        return Err(native::Error::InvalidArgument); +    }; + +    let _ = fs::write(path, content); + +    Ok(Primitive::Empty) +} + +pub const FILE_WRITE: NativeFunction = NativeFunction { +    name: "file$write", +    function: file_write, +    arity: 2, +    returns_value: false, +    doc: Some( +        "NativeFunction file$write: \n\targs: path (str), content (str)\n\tdesc: Writes <content> \ +         to file at <path>\n\tExample: `file$write('/home/sloth/todo.txt', 'Take a nap'); # \ +         todo.txt now contains the string 'Take a nap'`", +    ), +}; diff --git a/crates/sloth_vm/src/sloth_std/misc.rs b/crates/sloth_vm/src/sloth_std/misc.rs new file mode 100644 index 0000000..ca08d1d --- /dev/null +++ b/crates/sloth_vm/src/sloth_std/misc.rs @@ -0,0 +1,39 @@ +use crate::native::{self, NativeFunction, NativeFunctionResult}; +use crate::value::{Object, ObjectType, Primitive}; +use crate::VM; + +fn get_doc(vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let Some(Primitive::Object(ptr)) = args.get(0).cloned() else { +        return Err(native::Error::InvalidArgument); +    }; + +    let object = vm +        .objects() +        .get(ptr as usize) +        .ok_or(native::Error::InvalidArgument)?; + +    let ObjectType::NativeFunction(fnc) = &object.typ else { +        return Err(native::Error::InvalidArgument); +    }; + +    let docs = fnc +        .doc +        .expect("Oopsie Poopsie the stringy no worky") +        .to_string(); +    let object = Object::new(ObjectType::String(docs)); +    let ptr = vm.objects_mut().allocate(object); + +    Ok(Primitive::Object(ptr as u32)) +} + +pub const DOCS: NativeFunction = NativeFunction { +    name: "docs", +    function: get_doc, +    arity: 1, +    returns_value: true, +    doc: Some( +        "NativeFunction docs: \n\targs: name (str)\n\tdesc: Returns documentaiton on a function \ +         with name <str>\n\tExample: `var doc = docs('wait'); # Returns the documentation of the \ +         'wait' function to doc`", +    ), +}; diff --git a/crates/sloth_vm/src/sloth_std/mod.rs b/crates/sloth_vm/src/sloth_std/mod.rs index 86611d7..ff761a6 100644 --- a/crates/sloth_vm/src/sloth_std/mod.rs +++ b/crates/sloth_vm/src/sloth_std/mod.rs @@ -4,8 +4,12 @@ use once_cell::sync::Lazy;  use crate::native::NativeFunction; +pub mod file; +pub mod misc;  pub mod rand;  pub mod stdio; +pub mod term; +pub mod time;  pub static NATIVE_LIBRARY: Lazy<HashMap<&'static str, NativeFunction>> = Lazy::new(|| {      let mut map = HashMap::new(); @@ -16,9 +20,24 @@ pub static NATIVE_LIBRARY: Lazy<HashMap<&'static str, NativeFunction>> = Lazy::n      // stdio      map.insert("write", stdio::WRITE_FUNCTION); +    map.insert("writeln", stdio::WRITELN_FUNCTION);      map.insert("read", stdio::READ_FUNCTION); +    // term +    map.insert("term$clear", term::TERM_CLEAR); +    map.insert("term$setpos", term::TERM_SETPOS); +      // filesystem +    // TODO: Make the files commands work by making a global file variable with +    // certain permissions created by 'file.open' instead of just reading the file. +    map.insert("file$read", file::FILE_READ); +    map.insert("file$write", file::FILE_WRITE); + +    // time +    map.insert("wait", time::WAIT); + +    // doc +    map.insert("docs", misc::DOCS);      map  }); diff --git a/crates/sloth_vm/src/sloth_std/rand.rs b/crates/sloth_vm/src/sloth_std/rand.rs index bae0606..870cca1 100644 --- a/crates/sloth_vm/src/sloth_std/rand.rs +++ b/crates/sloth_vm/src/sloth_std/rand.rs @@ -16,6 +16,10 @@ pub const GEN_FUNCTION: NativeFunction = NativeFunction {      function: gen,      arity: 0,      returns_value: true, +    doc: Some( +        "NativeFunction rand$gen:\n\tdesc: Returns a random number in the range `0.0 .. \ +         1.0`\n\tExample: `var num = rand$gen(); # num could be any number from 0.0 to 1.0`", +    ),  };  fn gen_range(_vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { @@ -36,4 +40,9 @@ pub const GEN_RANGE_FUNCTION: NativeFunction = NativeFunction {      function: gen_range,      arity: 2,      returns_value: true, +    doc: Some( +        "NativeFunction rand$gen_range: \n\targs: min (int), max (int)\n\tdesc: Returns a random \ +         numnber in the range <min> .. <max>\n\tExample: `var num = rand$gen_range(20, 76); # num \ +         could be any number from 20 to 76`", +    ),  }; diff --git a/crates/sloth_vm/src/sloth_std/stdio.rs b/crates/sloth_vm/src/sloth_std/stdio.rs index a743ad1..f56b604 100644 --- a/crates/sloth_vm/src/sloth_std/stdio.rs +++ b/crates/sloth_vm/src/sloth_std/stdio.rs @@ -18,7 +18,7 @@ fn write(vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult {          return Err(native::Error::InvalidArgument);      }; -    println!("{str}"); +    print!("{str}");      Ok(Primitive::Empty)  } @@ -28,6 +28,41 @@ pub const WRITE_FUNCTION: NativeFunction = NativeFunction {      function: write,      arity: 1,      returns_value: false, +    doc: Some( +        "NativeFunction write: \n\targs: string (str)\n\tdesc: Writes <string> to the \ +         terminal.\n\tExample: `write(\"I'm sleepy...\"); # Output: I'm sleepy...`", +    ), +}; + +fn writeln(vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let Some(Primitive::Object(ptr)) = args.get(0).cloned() else { +        return Err(native::Error::InvalidArgument); +    }; + +    let object = vm +        .objects() +        .get(ptr as usize) +        .ok_or(native::Error::InvalidArgument)?; + +    let ObjectType::String(str) = &object.typ else { +        return Err(native::Error::InvalidArgument); +    }; + +    println!("{str}"); + +    Ok(Primitive::Empty) +} + +pub const WRITELN_FUNCTION: NativeFunction = NativeFunction { +    name: "writeln", +    function: writeln, +    arity: 1, +    returns_value: false, +    doc: Some( +        "NativeFunction writeln: \n\targs: string (str)\n\tdesc: Writes <string> to the terminal \ +         and starts a new line.\n\tExample: `writeln(\"I'm sleepy...\"); # Output: I'm \ +         sleepy...\n # This is a new line`", +    ),  };  fn read(vm: &mut VM, _args: &[Primitive]) -> NativeFunctionResult { @@ -48,4 +83,9 @@ pub const READ_FUNCTION: NativeFunction = NativeFunction {      function: read,      arity: 0,      returns_value: true, +    doc: Some( +        "NativeFunction read:\n\tdesc: Reads input from the terminal and returns what was \ +         read.\n\tExample: `var input = read(); # Hello World <execute code> input = 'Hello \ +         World'`", +    ),  }; diff --git a/crates/sloth_vm/src/sloth_std/term.rs b/crates/sloth_vm/src/sloth_std/term.rs new file mode 100644 index 0000000..f61321c --- /dev/null +++ b/crates/sloth_vm/src/sloth_std/term.rs @@ -0,0 +1,41 @@ +use crate::native::{self, NativeFunction, NativeFunctionResult}; +use crate::value::Primitive; +use crate::value::Primitive::Integer; +use crate::VM; + +pub const TERM_CLEAR: NativeFunction = NativeFunction { +    name: "term$clear", +    function: |_vm, _args| { +        print!("\x1b[2J\x1b[H"); +        Ok(Primitive::Empty) +    }, +    arity: 0, +    returns_value: false, +    doc: Some( +        "NativeFunction term$clear: \n\tdesc: Clears the terminal\n\tExample: `term$clear(); # \ +         Clears the terminal`", +    ), +}; + +fn term_setpos(_vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let x = args.get(0).cloned(); +    let y = args.get(1).cloned(); + +    let (Some(Integer(x)), Some(Integer(y))) = (x, y) else { +        return Err(native::Error::InvalidArgument); +    }; +    print!("\x1b[{x};{y}H"); +    Ok(Primitive::Empty) +} + +pub const TERM_SETPOS: NativeFunction = NativeFunction { +    name: "term$setpos", +    function: term_setpos, +    arity: 2, +    returns_value: false, +    doc: Some( +        "NativeFunction term$setpos: \n\targs: x (int), y (int)\n\tdesc: Sets the cursors \ +         position to (<x>, <y>)\n\tExample: `term$setpos(5, 17); # Sets the position of the \ +         cursor to (5, 17)`", +    ), +}; diff --git a/crates/sloth_vm/src/sloth_std/time.rs b/crates/sloth_vm/src/sloth_std/time.rs new file mode 100644 index 0000000..b27e0b5 --- /dev/null +++ b/crates/sloth_vm/src/sloth_std/time.rs @@ -0,0 +1,29 @@ +use std::{thread, time}; + +use crate::native::{self, NativeFunction, NativeFunctionResult}; +use crate::value::Primitive; +use crate::value::Primitive::Integer; +use crate::VM; + +fn wait(_vm: &mut VM, args: &[Primitive]) -> NativeFunctionResult { +    let sec = args.get(0).cloned(); + +    let Some(Integer(sec)) = sec else { +        return Err(native::Error::InvalidArgument); +    }; + +    thread::sleep(time::Duration::from_secs(sec.try_into().unwrap())); + +    Ok(Primitive::Empty) +} + +pub const WAIT: NativeFunction = NativeFunction { +    name: "wait", +    function: wait, +    arity: 1, +    returns_value: false, +    doc: Some( +        "NativeFunction wait: \n\targs: sec (int)\n\tdesc: Waits for <sec> seconds.\n\tExample: \ +         `wait(10); # Waits 10 seconds`", +    ), +}; | 
