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)]
|
#[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)
|
||||||
|
|||||||
Reference in New Issue
Block a user