Amo/src/parser/declaration.rs

85 lines
2.4 KiB
Rust

use std::mem::{Discriminant, discriminant};
use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope}};
use super::{Parsable, WrappedLexer, ParseError, absorb_token_or_error, expr::Expr};
#[derive(Debug)]
pub struct Declaration {
name: String,
type_: Expr,
name2: String,
args: Vec<String>,
value: Expr,
}
impl Parsable for Declaration {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
(vec![
discriminant(&Token::Symbol("".to_string())),
], false)
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
let span = l.span();
match l.monch() {
// Symbol Colon <full_type> DeclarationStart Symbol { Symbol } Assign <expr>
Token::Symbol(name) => {
absorb_token_or_error(l, discriminant(&Token::Colon))?;
let type_ = Expr::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::DeclarationStart))?;
let name2 = String::parse(l)?;
let args = Vec::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::Assign))?;
let value = Expr::parse(l)?;
Ok(Self {
name,
name2,
args,
type_,
value,
})
},
_ => {
Err(ParseError {
expected: Self::expected().0,
location: span,
})
}
}
}
}
impl Declaration {
pub fn gen_ir(self, bindings: &BindingScope, index: u32, parent_id: Identifier) -> Result<Option<ir::Declaration>, IrError> {
let own_id = self.get_identifier(&parent_id, index).unwrap(); //TODO fix me
let Declaration { name, type_, name2, args, value } = self;
if name != name2 {
Err(IrError::MismatchedNames(name, name2))
} else {
let args = args.into_iter()
.enumerate()
.map(|(i, variable_name)| own_id.subid_with_name(variable_name, i as u32))
.collect::<Vec<_>>();
let n_args = args.len() as u32;
let local_binding = bindings.bind(args.clone());
let expression_dag = value.gen_ir(&local_binding, &own_id, n_args, false)?;
let type_dag = type_.gen_ir(&local_binding, &own_id, n_args + 1, true)?;
Ok(Some(
ir::Declaration {
identifier: own_id,
value_type: ir::value::Value::Function(Vec::new(), type_dag),
value: ir::value::Value::Function(args, expression_dag),
}
))
}
}
pub fn get_identifier(&self, parent: &Identifier, index: u32) -> Option<Identifier> {
if self.name.eq("main") {
Some(Identifier::main())
} else {
Some(parent.subid_with_name(self.name.clone(), index))
}
}
}