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)]
pub struct RoutineName(pub String);
pub struct RoutineName { pub name: String, pub arity: u8 }
impl Display for RoutineName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
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)
write!(f, "{}/{}", self.name, self.arity)
}
}

@ -5,6 +5,7 @@ use thiserror::Error;
use crate::asm::data::{Mask, Register};
use crate::asm::data::literal::Label;
use crate::asm::instr::Cond;
use std::num::ParseIntError;
/// csn_asm unified error type
#[derive(Error, Debug)]
@ -23,6 +24,12 @@ pub enum CrsnError {
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)
#[derive(Error, Debug)]
pub enum AsmError {

@ -8,11 +8,23 @@ use crate::asm::patches::SexpIsA;
use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::data::Register;
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> {
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);
// 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());
{
@ -41,7 +53,7 @@ pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserCon
}
return Ok(Box::new(Routine {
name: RoutineName(name),
name,
body,
}));
}

@ -120,7 +120,7 @@ impl CrsnExtension for BuiltinOps {
}
"call" => {
let dest = RoutineName(args.next_string()?);
let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 };
let mut call_args = vec![];
for t in args {
@ -138,8 +138,8 @@ impl CrsnExtension for BuiltinOps {
}
"routine" => {
let dest = RoutineName(args.next_string()?);
BuiltinOp::Routine(dest)
let name = args.next_string()?;
BuiltinOp::Routine(parse_routine_name(name)?)
}
"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)
(halt)
(proc fac
(proc fac/1
(cmp arg0 2
(eq? (ret 2)))
(sub r0 arg0 1)

Loading…
Cancel
Save