diff --git a/src/lntors/event.rs b/src/lntors/event.rs index d60cc29b..bd7390ee 100644 --- a/src/lntors/event.rs +++ b/src/lntors/event.rs @@ -101,7 +101,7 @@ pub fn generate( // If it's a bound function, just call it with the argument, if there // is one let arg_str = match &handler_fn.microstatements[0] { - Microstatement::Arg { name, .. } => name.clone(), + Microstatement::Arg { name, .. } => format!("&{}", name).to_string(), _ => "".to_string(), }; out = format!("{} super::{}({});\n", out, b, arg_str); diff --git a/src/lntors/function.rs b/src/lntors/function.rs index 5a4ae74b..7f63d56d 100644 --- a/src/lntors/function.rs +++ b/src/lntors/function.rs @@ -12,7 +12,14 @@ pub fn from_microstatement( mut out: OrderedHashMap, ) -> Result<(String, OrderedHashMap), Box> { match microstatement { - Microstatement::Arg { .. } => Ok(("".to_string(), out)), // Skip arg microstatements that are just used for discovery during generation + Microstatement::Arg { name, .. } => { + // TODO: Update the serialization logic to understand values vs references so we can + // eliminate this useless (and harmful for mutable references) clone + Ok(( + format!("let {} = {}.clone()", name, name).to_string(), + out, + )) + } Microstatement::Assignment { name, value, @@ -24,8 +31,8 @@ pub fn from_microstatement( out = o; Ok(( format!( - "let {} {} = {}", - if *mutable { "mut" } else { "" }, + "let {}{} = {}", + if *mutable { "mut " } else { "" }, name, val, ) @@ -103,7 +110,15 @@ pub fn from_microstatement( for arg in args { let (a, o) = from_microstatement(arg, scope, program, out)?; out = o; - argstrs.push(a); + // If the argument is itself a function, this is the only place in Rust + // where you can't pass by reference, so we check the type and change + // the argument output accordingly. + let arg_type = arg.get_type(scope, program)?; + if arg_type.as_str() == "function" { + argstrs.push(format!("{}", a)); + } else { + argstrs.push(format!("&{}", a)); + } } Ok(( format!("{}({})", rustname, argstrs.join(", ")).to_string(), @@ -115,7 +130,15 @@ pub fn from_microstatement( for arg in args { let (a, o) = from_microstatement(arg, scope, program, out)?; out = o; - argstrs.push(a); + // If the argument is itself a function, this is the only place in Rust + // where you can't pass by reference, so we check the type and change + // the argument output accordingly. + let arg_type = arg.get_type(scope, program)?; + if arg_type.as_str() == "function" { + argstrs.push(format!("{}", a)); + } else { + argstrs.push(format!("&{}", a)); + } } Ok(( format!("{}({})", rustname, argstrs.join(", ")).to_string(), @@ -157,7 +180,7 @@ pub fn generate( for arg in &function.args { if let Some((t, s)) = program.resolve_type(scope, &arg.1) { if let Ok(t_str) = typen::generate(t, s, program) { - arg_strs.push(format!("{}: {}", arg.0, t_str).to_string()); + arg_strs.push(format!("{}: &{}", arg.0, t_str).to_string()); } else { return Err(format!("Failed to convert Alan type {} to Rust", &arg.1).into()); } diff --git a/src/std/root.ln b/src/std/root.ln index 41434e3c..9d921712 100644 --- a/src/std/root.ln +++ b/src/std/root.ln @@ -6,7 +6,7 @@ // Integer-related bindings export type i8 binds i8; export type Result binds Result_i8; -export fn ok(i: i8): Result binds Ok; +export fn ok(i: i8): Result binds alan_ok; export fn getOr(r: Result, default: i8): i8 binds get_or_i8; export fn i8(i: i64): i8 binds i64toi8; export fn add(a: i8, b: i8): Result binds addi8; @@ -63,7 +63,7 @@ export fn min(a: i32, b: i32): i32 binds mini32; export fn max(a: i32, b: i32): i32 binds maxi32; export type i64 binds i64; export type Result binds Result_i64; -export fn ok(i: i64): Result binds Ok; +export fn ok(i: i64): Result binds alan_ok; export fn getOr(r: Result, default: i64): i64 binds get_or_i64; export fn i64(i: i64): i64 = i; export fn add(a: i64, b: i64): Result binds addi64; diff --git a/src/std/root.rs b/src/std/root.rs index 6a7db15e..52a9987d 100644 --- a/src/std/root.rs +++ b/src/std/root.rs @@ -1,39 +1,76 @@ /// Rust functions that the root scope binds. +/// The `AlanError` type is a *cloneable* error that all errors are implemented as within Alan, to +/// simplify error handling. In the future it will have a stack trace based on the Alan source +/// code, but for now only a simple error message is provided. +#[derive(Clone, Debug)] +struct AlanError { + message: String, +} + +impl std::fmt::Display for AlanError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Error: {}", self.message) + } +} + +impl std::error::Error for AlanError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +impl From<&str> for AlanError { + fn from(s: &str) -> AlanError { + AlanError { + message: s.to_string(), + } + } +} + +/// `alan_ok` is a wrapper function that takes a reference to a value, clones it, and returns it as +/// a Result-wrapped value. Hopefully this weird function will die soon. +fn alan_ok(val: &A) -> Result { + Ok(val.clone()) +} + /// `to_exit_code_i8` converts a 64-bit integer into an exit code, for convenience since `i64` is the /// default integer type in Alan. -fn to_exit_code_i8(i: i8) -> std::process::ExitCode { - (i as u8).into() +fn to_exit_code_i8(i: &i8) -> std::process::ExitCode { + (*i as u8).into() } /// `i64toi8` casts an i64 to an i8. -fn i64toi8(i: i64) -> i8 { - i as i8 +fn i64toi8(i: &i64) -> i8 { + *i as i8 } -/// `Result_i8` is a type alias for Result> -type Result_i8 = Result>; +/// `Result_i8` is a type alias for Result +type Result_i8 = Result; /// `get_or_i8` unwraps a Result_i8 with the default value if it is an error -fn get_or_i8(r: Result_i8, default: i8) -> i8 { - r.unwrap_or(default) +fn get_or_i8(r: &Result_i8, default: &i8) -> i8 { + match r { + Ok(v) => *v, + Err(_) => *default, + } } /// `addi8` safely adds two i8s together, returning a Result-wrapped i8 (or an error on overflow) -fn addi8(a: i8, b: i8) -> Result_i8 { - match a.checked_add(b) { +fn addi8(a: &i8, b: &i8) -> Result_i8 { + match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } } /// `addi8_result` safely adds two Result_i8s together, returning a Result-wrapped i8 (or an error on overflow) -fn addi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn addi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_add(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } @@ -42,20 +79,20 @@ fn addi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `subi8` safely subtracts two i8s, returning a Result-wrapped i8 (or an error on underflow) -fn subi8(a: i8, b: i8) -> Result_i8 { - match a.checked_sub(b) { +fn subi8(a: &i8, b: &i8) -> Result_i8 { + match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } } /// `subi8_result` safely subtracts two i8s, returning a Result-wrapped i8 (or an error on underflow) -fn subi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn subi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_sub(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } @@ -64,20 +101,20 @@ fn subi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `muli8` safely multiplies two i8s, returning a Result-wrapped i8 (or an error on under/overflow) -fn muli8(a: i8, b: i8) -> Result_i8 { - match a.checked_mul(b) { +fn muli8(a: &i8, b: &i8) -> Result_i8 { + match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `muli8_result` safely multiplies two Result_i8s, returning a Result-wrapped i8 (or an error on under/overflow) -fn muli8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn muli8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_mul(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } @@ -86,20 +123,20 @@ fn muli8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `divi8` safely divides two i8s, returning a Result-wrapped i8 (or an error on divide-by-zero) -fn divi8(a: i8, b: i8) -> Result_i8 { - match a.checked_div(b) { +fn divi8(a: &i8, b: &i8) -> Result_i8 { + match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `divi8_result` safely divides two Result_i8s, returning a Result-wrapped i8 (or an error on divide-by-zero) -fn divi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn divi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_div(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } @@ -108,20 +145,20 @@ fn divi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `modi8` safely divides two i8s, returning a Result-wrapped remainder in i8 (or an error on divide-by-zero) -fn modi8(a: i8, b: i8) -> Result_i8 { - match a.checked_rem(b) { +fn modi8(a: &i8, b: &i8) -> Result_i8 { + match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `modi8_result` safely divides two Result_i8s, returning a Result-wrapped remainder in i8 (or an error on divide-by-zero) -fn modi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn modi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_rem(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } @@ -130,22 +167,22 @@ fn modi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `powi8` safely raises the first i8 to the second i8, returning a Result-wrapped i8 (or an error on under/overflow) -fn powi8(a: i8, b: i8) -> Result_i8 { +fn powi8(a: &i8, b: &i8) -> Result_i8 { // TODO: Support b being negative correctly - match a.checked_pow(b as u32) { + match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `powi8_result` safely raises the first Result_i8 to the second Result_i8, returning a Result-wrapped i8 (or an error on under/overflow) -fn powi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn powi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { // TODO: Support b being negative correctly match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_pow(b as u32) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } @@ -154,188 +191,197 @@ fn powi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { } /// `mini8` returns the smaller of the two i8 values -fn mini8(a: i8, b: i8) -> i8 { - if a < b { a } else { b } +fn mini8(a: &i8, b: &i8) -> i8 { + if a < b { *a } else { *b } } /// `mini8_result` returns the smaller of the two Result_i8 values -fn mini8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn mini8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => if a < b { Ok(a) } else { Ok(b) } + Err(e) => Err(e.clone()), + Ok(b) => if a < b { Ok(*a) } else { Ok(*b) } } } } /// `maxi8` returns the larger of the two i8 values -fn maxi8(a: i8, b: i8) -> i8 { - if a > b { a } else { b } +fn maxi8(a: &i8, b: &i8) -> i8 { + if a > b { *a } else { *b } } /// `maxi8_result` returns the larger of the two Result_i8 values -fn maxi8_result(a: Result_i8, b: Result_i8) -> Result_i8 { +fn maxi8_result(a: &Result_i8, b: &Result_i8) -> Result_i8 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => if a > b { Ok(a) } else { Ok(b) } + Err(e) => Err(e.clone()), + Ok(b) => if a > b { Ok(*a) } else { Ok(*b) } } } } /// `i64toi16` casts an i64 to an i16. -fn i64toi16(i: i64) -> i16 { - i as i16 +fn i64toi16(i: &i64) -> i16 { + *i as i16 } +/// `Result_i16` is a type alias for Result +type Result_i16 = Result; + /// `addi16` safely adds two i16s together, returning a Result-wrapped i16 (or an error on overflow) -fn addi16(a: i16, b: i16) -> Result> { - match a.checked_add(b) { +fn addi16(a: &i16, b: &i16) -> Result_i16 { + match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } } /// `subi16` safely subtracts two i16s, returning a Result-wrapped i16 (or an error on underflow) -fn subi16(a: i16, b: i16) -> Result> { - match a.checked_sub(b) { +fn subi16(a: &i16, b: &i16) -> Result_i16 { + match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } } /// `muli16` safely multiplies two i16s, returning a Result-wrapped i16 (or an error on under/overflow) -fn muli16(a: i16, b: i16) -> Result> { - match a.checked_mul(b) { +fn muli16(a: &i16, b: &i16) -> Result_i16 { + match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `divi16` safely divides two i16s, returning a Result-wrapped i16 (or an error on divide-by-zero) -fn divi16(a: i16, b: i16) -> Result> { - match a.checked_div(b) { +fn divi16(a: &i16, b: &i16) -> Result_i16 { + match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `modi16` safely divides two i16s, returning a Result-wrapped remainder in i16 (or an error on divide-by-zero) -fn modi16(a: i16, b: i16) -> Result> { - match a.checked_rem(b) { +fn modi16(a: &i16, b: &i16) -> Result_i16 { + match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `powi16` safely raises the first i16 to the second i16, returning a Result-wrapped i16 (or an error on under/overflow) -fn powi16(a: i16, b: i16) -> Result> { +fn powi16(a: &i16, b: &i16) -> Result_i16 { // TODO: Support b being negative correctly - match a.checked_pow(b as u32) { + match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `mini16` returns the smaller of the two i16 values -fn mini16(a: i16, b: i16) -> i16 { - if a < b { a } else { b } +fn mini16(a: &i16, b: &i16) -> i16 { + if a < b { *a } else { *b } } /// `maxi16` returns the larger of the two i16 values -fn maxi16(a: i16, b: i16) -> i16 { - if a > b { a } else { b } +fn maxi16(a: &i16, b: &i16) -> i16 { + if a > b { *a } else { *b } } +/// `Result_i32` is a type alias for Result +type Result_i32 = Result; + /// `i64toi32` casts an i64 to an i32. -fn i64toi32(i: i64) -> i32 { - i as i32 +fn i64toi32(i: &i64) -> i32 { + *i as i32 } /// `addi32` safely adds two i32s together, returning a Result-wrapped i32 (or an error on overflow) -fn addi32(a: i32, b: i32) -> Result> { - match a.checked_add(b) { +fn addi32(a: &i32, b: &i32) -> Result_i32 { + match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } } /// `subi32` safely subtracts two i32s, returning a Result-wrapped i32 (or an error on underflow) -fn subi32(a: i32, b: i32) -> Result> { - match a.checked_sub(b) { +fn subi32(a: &i32, b: &i32) -> Result_i32 { + match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } } /// `muli32` safely multiplies two i32s, returning a Result-wrapped i32 (or an error on under/overflow) -fn muli32(a: i32, b: i32) -> Result> { - match a.checked_mul(b) { +fn muli32(a: &i32, b: &i32) -> Result_i32 { + match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `divi32` safely divides two i32s, returning a Result-wrapped i32 (or an error on divide-by-zero) -fn divi32(a: i32, b: i32) -> Result> { - match a.checked_div(b) { +fn divi32(a: &i32, b: &i32) -> Result_i32 { + match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `modi32` safely divides two i32s, returning a Result-wrapped remainder in i32 (or an error on divide-by-zero) -fn modi32(a: i32, b: i32) -> Result> { - match a.checked_rem(b) { +fn modi32(a: &i32, b: &i32) -> Result_i32 { + match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `powi32` safely raises the first i32 to the second i32, returning a Result-wrapped i32 (or an error on under/overflow) -fn powi32(a: i32, b: i32) -> Result> { +fn powi32(a: &i32, b: &i32) -> Result_i32 { // TODO: Support b being negative correctly - match a.checked_pow(b as u32) { + match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `mini32` returns the smaller of the two i32 values -fn mini32(a: i32, b: i32) -> i32 { - if a < b { a } else { b } +fn mini32(a: &i32, b: &i32) -> i32 { + if a < b { *a } else { *b } } /// `maxi32` returns the larger of the two i32 values -fn maxi32(a: i32, b: i32) -> i32 { - if a > b { a } else { b } +fn maxi32(a: &i32, b: &i32) -> i32 { + if a > b { *a } else { *b } } -/// `Result_i64` is a type alias for Result> -type Result_i64 = Result>; +/// `Result_i64` is a type alias for Result +type Result_i64 = Result; /// `get_or_i64` unwraps a Result_i64 with the default value if it is an error -fn get_or_i64(r: Result_i64, default: i64) -> i64 { - r.unwrap_or(default) +fn get_or_i64(r: &Result_i64, default: &i64) -> i64 { + match r { + Ok(v) => *v, + Err(_) => *default, + } } /// `addi64` safely adds two i64s together, returning a Result-wrapped i64 (or an error on overflow) -fn addi64(a: i64, b: i64) -> Result_i64 { - match a.checked_add(b) { +fn addi64(a: &i64, b: &i64) -> Result_i64 { + match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } } /// `addi64_result` safely adds two Result_i64s together, returning a Result-wrapped i64 (or an error on overflow) -fn addi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn addi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_add(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_add(*b) { Some(c) => Ok(c), None => Err("Overflow".into()), } @@ -344,20 +390,20 @@ fn addi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `subi64` safely subtracts two i64s, returning a Result-wrapped i64 (or an error on underflow) -fn subi64(a: i64, b: i64) -> Result_i64 { - match a.checked_sub(b) { +fn subi64(a: &i64, b: &i64) -> Result_i64 { + match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } } /// `subi64_result` safely subtracts two Result_i64s, returning a Result-wrapped i64 (or an error on underflow) -fn subi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn subi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_sub(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_sub(*b) { Some(c) => Ok(c), None => Err("Underflow".into()), } @@ -366,20 +412,20 @@ fn subi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `muli64` safely multiplies two i64s, returning a Result-wrapped i64 (or an error on under/overflow) -fn muli64(a: i64, b: i64) -> Result_i64 { - match a.checked_mul(b) { +fn muli64(a: &i64, b: &i64) -> Result_i64 { + match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `muli64_result` safely multiplies two Result_i64s, returning a Result-wrapped i64 (or an error on under/overflow) -fn muli64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn muli64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_mul(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_mul(*b) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } @@ -388,20 +434,20 @@ fn muli64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `divi64` safely divides two i64s, returning a Result-wrapped i64 (or an error on divide-by-zero) -fn divi64(a: i64, b: i64) -> Result_i64 { - match a.checked_div(b) { +fn divi64(a: &i64, b: &i64) -> Result_i64 { + match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `divi64_result` safely divides two Resul_i64s, returning a Result-wrapped i64 (or an error on divide-by-zero) -fn divi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn divi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_div(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_div(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } @@ -410,20 +456,20 @@ fn divi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `modi64` safely divides two i64s, returning a Result-wrapped remainder in i64 (or an error on divide-by-zero) -fn modi64(a: i64, b: i64) -> Result_i64 { - match a.checked_rem(b) { +fn modi64(a: &i64, b: &i64) -> Result_i64 { + match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } } /// `modi64_result` safely divides two Result_i64s, returning a Result-wrapped remainder in i64 (or an error on divide-by-zero) -fn modi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn modi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_rem(b) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_rem(*b) { Some(c) => Ok(c), None => Err("Divide-by-zero".into()), } @@ -432,22 +478,22 @@ fn modi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `powi64` safely raises the first i64 to the second i64, returning a Result-wrapped i64 (or an error on under/overflow) -fn powi64(a: i64, b: i64) -> Result_i64 { +fn powi64(a: &i64, b: &i64) -> Result_i64 { // TODO: Support b being negative correctly - match a.checked_pow(b as u32) { + match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } } /// `powi64_result` safely raises the first Result_i64 to the second Result_i64, returning a Result-wrapped i64 (or an error on under/overflow) -fn powi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn powi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { // TODO: Support b being negative correctly match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => match a.checked_pow(b as u32) { + Err(e) => Err(e.clone()), + Ok(b) => match a.checked_pow(*b as u32) { Some(c) => Ok(c), None => Err("Underflow or Overflow".into()), } @@ -456,54 +502,57 @@ fn powi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { } /// `mini64` returns the smaller of the two i64 values -fn mini64(a: i64, b: i64) -> i64 { - if a < b { a } else { b } +fn mini64(a: &i64, b: &i64) -> i64 { + if a < b { *a } else { *b } } /// `mini64_result` returns the smaller of the two Result_i64 values -fn mini64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn mini64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => if a < b { Ok(a) } else { Ok(b) } + Err(e) => Err(e.clone()), + Ok(b) => if a < b { Ok(*a) } else { Ok(*b) } } } } /// `maxi64` returns the larger of the two i64 values -fn maxi64(a: i64, b: i64) -> i64 { - if a > b { a } else { b } +fn maxi64(a: &i64, b: &i64) -> i64 { + if a > b { *a } else { *b } } /// `maxi64_result` returns the larger of the two Result_i64 values -fn maxi64_result(a: Result_i64, b: Result_i64) -> Result_i64 { +fn maxi64_result(a: &Result_i64, b: &Result_i64) -> Result_i64 { match a { - Err(e) => Err(e), + Err(e) => Err(e.clone()), Ok(a) => match b { - Err(e) => Err(e), - Ok(b) => if a > b { Ok(a) } else { Ok(b) } + Err(e) => Err(e.clone()), + Ok(b) => if a > b { Ok(*a) } else { Ok(*b) } } } } /// `get_or_exit` is basically an alias to `unwrap`, but as a function instead of a method -fn get_or_exit(a: Result>) -> A { - a.unwrap() +fn get_or_exit(a: &Result) -> A { + match a { + Ok(v) => v.clone(), + Err(e) => panic!("{:?}", e), + } } /// `string_concat` is a simple function that concatenates two strings -fn string_concat(a: String, b: String) -> String { +fn string_concat(a: &String, b: &String) -> String { format!("{}{}", a, b).to_string() } /// `println` is a simple function that prints basically anything -fn println(a: A) { +fn println(a: &A) { println!("{}", a); } /// `println_result` is a small wrapper function that makes printing Result types easy -fn println_result(a: Result>) { +fn println_result(a: &Result) { match a { Ok(o) => println!("{}", o), Err(e) => println!("{:?}", e), @@ -511,13 +560,13 @@ fn println_result(a: Result> } /// `stdout` is a simple function that prints basically anything without a newline attached -fn stdout(a: A) { +fn stdout(a: &A) { print!("{}", a); } /// `wait` is a function that sleeps the current thread for the specified number of milliseconds -fn wait(t: i64) { - std::thread::sleep(std::time::Duration::from_millis(t as u64)); +fn wait(t: &i64) { + std::thread::sleep(std::time::Duration::from_millis(*t as u64)); } /// `now` is a function that returns std::time::Instant for right now @@ -526,27 +575,27 @@ fn now() -> std::time::Instant { } /// `elapsed` gets the duration since the instant was created TODO: Borrow these values instead -fn elapsed(i: std::time::Instant) -> std::time::Duration { +fn elapsed(i: &std::time::Instant) -> std::time::Duration { i.elapsed() } /// `print_duration` pretty-prints a duration value. TODO: Move this into Alan code and out of here -fn print_duration(d: std::time::Duration) { +fn print_duration(d: &std::time::Duration) { println!("{}.{:0>9}", d.as_secs(), d.subsec_nanos()); // TODO: Figure out which subsec to use } /// `filled` returns a filled Vec of the provided value for the provided size -fn filled(i: V, l: i64) -> Vec { - vec![i; l as usize] +fn filled(i: &V, l: &i64) -> Vec { + vec![i.clone(); *l as usize] } /// `print_vec` pretty prints a vector assuming the input type can be displayed -fn print_vec(vs: Vec) { +fn print_vec(vs: &Vec) { println!("[{}]", vs.iter().map(|v| format!("{}", v)).collect::>().join(", ")); } /// `print_vec_result` pretty prints a vector of result values assuming the input can be displayed -fn print_vec_result(vs: Vec>>) { +fn print_vec_result(vs: &Vec>) { println!("[{}]", vs.iter().map(|v| match v { Err(e) => format!("{:?}", e), Ok(a) => format!("{}", a) @@ -555,18 +604,18 @@ fn print_vec_result(vs: Vec(v: Vec, m: fn(A) -> B) -> Vec { - v.iter().map(|val| m(val.clone())).collect::>() +fn map_onearg(v: &Vec, m: fn(&A) -> B) -> Vec { + v.iter().map(|val| m(val)).collect::>() } /// `map_twoarg` runs the provided two-argument (value, index) function on each element of the /// vector, returning a new vector -fn map_twoarg(v: Vec, m: fn(&A, usize) -> B) -> Vec { +fn map_twoarg(v: &Vec, m: fn(&A, usize) -> B) -> Vec { v.iter().enumerate().map(|(i, val)| m(val, i)).collect::>() } /// `map_threearg` runs the provided three-argument (value, index, vec_ref) function on each /// element of the vector, returning a new vector -fn map_threearg(v: Vec, m: fn(&A, usize, &Vec) -> B) -> Vec { +fn map_threearg(v: &Vec, m: fn(&A, usize, &Vec) -> B) -> Vec { v.iter().enumerate().map(|(i, val)| m(val, i, &v)).collect::>() } \ No newline at end of file