Routine arity disambiguation, slash syntax (add/2, add/3)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user