Routine arity disambiguation, slash syntax (add/2, add/3)

pull/21/head
Ondřej Hruška 4 years ago
parent 8d585d765b
commit e0cc1973ba
  1. 18
      crsn/src/asm/data/literal.rs
  2. 7
      crsn/src/asm/error.rs
  3. 14
      crsn/src/asm/parse/parse_routine.rs
  4. 19
      crsn/src/builtin/parse.rs
  5. 48
      examples/arities.csn
  6. 2
      examples/factorial.csn

@ -103,25 +103,13 @@ impl From<String> for Label {
} }
} }
/// Routine name /// Routine name, including the routine's arity
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct RoutineName(pub String); pub struct RoutineName { pub name: String, pub arity: u8 }
impl Display for RoutineName { impl Display for RoutineName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0) write!(f, "{}/{}", self.name, self.arity)
}
}
impl From<&str> for RoutineName {
fn from(n: &str) -> Self {
Self(n.to_string())
}
}
impl From<String> for RoutineName {
fn from(n: String) -> Self {
Self(n)
} }
} }

@ -5,6 +5,7 @@ use thiserror::Error;
use crate::asm::data::{Mask, Register}; use crate::asm::data::{Mask, Register};
use crate::asm::data::literal::Label; use crate::asm::data::literal::Label;
use crate::asm::instr::Cond; use crate::asm::instr::Cond;
use std::num::ParseIntError;
/// csn_asm unified error type /// csn_asm unified error type
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -23,6 +24,12 @@ pub enum CrsnError {
Other(#[from] anyhow::Error), Other(#[from] anyhow::Error),
} }
impl From<std::num::ParseIntError> for CrsnError {
fn from(e: ParseIntError) -> Self {
CrsnError::Other(anyhow::anyhow!(e))
}
}
/// Error from the assembler stage (after parsing S-expressions and basic validation) /// Error from the assembler stage (after parsing S-expressions and basic validation)
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum AsmError { pub enum AsmError {

@ -8,11 +8,23 @@ use crate::asm::patches::SexpIsA;
use crate::asm::parse::parse_data::parse_reg_alias; use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::data::Register; use crate::asm::data::Register;
use crate::asm::data::literal::RoutineName; use crate::asm::data::literal::RoutineName;
use crate::builtin::parse::parse_routine_name;
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> { pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
let name = expect_string_atom(toki.next())?; let name = expect_string_atom(toki.next())?;
let mut name = parse_routine_name(name)?;
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx); let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx);
// If arity is explicitly given, then either no named argument must be provided,
// or their count must match the arity. If no arity is given, then arity is determined
// by the number of named arguments.
if name.arity == 0 && arg_tokens.len() != 0 {
name.arity = arg_tokens.len() as u8;
} else if arg_tokens.len() != 0 && name.arity as usize != arg_tokens.len() {
return Err(CrsnError::Parse(format!("arity mismatch in routine {}", name.name).into()));
}
let toki = toki.skip_while(|e| e.is_atom()); let toki = toki.skip_while(|e| e.is_atom());
{ {
@ -41,7 +53,7 @@ pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserCon
} }
return Ok(Box::new(Routine { return Ok(Box::new(Routine {
name: RoutineName(name), name,
body, body,
})); }));
} }

@ -120,7 +120,7 @@ impl CrsnExtension for BuiltinOps {
} }
"call" => { "call" => {
let dest = RoutineName(args.next_string()?); let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 };
let mut call_args = vec![]; let mut call_args = vec![];
for t in args { for t in args {
@ -138,8 +138,8 @@ impl CrsnExtension for BuiltinOps {
} }
"routine" => { "routine" => {
let dest = RoutineName(args.next_string()?); let name = args.next_string()?;
BuiltinOp::Routine(dest) BuiltinOp::Routine(parse_routine_name(name)?)
} }
"sk" => { "sk" => {
@ -227,3 +227,16 @@ impl CrsnExtension for BuiltinOps {
}))) })))
} }
} }
pub(crate) fn parse_routine_name(name : String) -> Result<RoutineName, CrsnError> {
let (name, arity) = if let Some(n) = name.find('/') {
(
(&name[0..n]).to_string(),
(&name[(n+1)..]).parse::<u8>()?
)
} else {
(name, 0)
};
Ok(RoutineName { name, arity })
}

@ -0,0 +1,48 @@
(
(call slash 1)
(cmp res0 1 (ne? (fault)))
(call named 2)
(cmp res0 2 (ne? (fault)))
(call both 3)
(cmp res0 3 (ne? (fault)))
(call slash 1 2)
(cmp res0 1 (ne? (fault)))
(cmp res1 2 (ne? (fault)))
(call named 2 3)
(cmp res0 2 (ne? (fault)))
(cmp res1 3 (ne? (fault)))
(call both 3 4)
(cmp res0 3 (ne? (fault)))
(cmp res1 4 (ne? (fault)))
(halt)
(proc slash/1
(ret arg0)
)
(proc slash/2
(ret arg0 arg1)
)
(proc named a
(ret a)
)
(proc named a b
(ret a b)
)
(proc both/1 a
(ret a)
)
(proc both/2 a b
(ret a b)
)
)

@ -3,7 +3,7 @@
(ld r0 res0) (ld r0 res0)
(halt) (halt)
(proc fac (proc fac/1
(cmp arg0 2 (cmp arg0 2
(eq? (ret 2))) (eq? (ret 2)))
(sub r0 arg0 1) (sub r0 arg0 1)

Loading…
Cancel
Save