Resolver - Check class methods against special member definitions
This commit is contained in:
parent
ef7068e027
commit
1377ba1a23
1 changed files with 51 additions and 7 deletions
|
@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{ClassMemberDecl, ClassMemberKind, ExprNode, ProgramNode, StmtNode, VariableExpr},
|
ast::{ClassMemberDecl, ClassMemberKind, ExprNode, ProgramNode, StmtNode, VariableExpr},
|
||||||
errors::{ErrorKind, SloxError, SloxResult},
|
errors::{ErrorKind, SloxError, SloxResult},
|
||||||
|
special,
|
||||||
tokens::Token,
|
tokens::Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -296,6 +297,55 @@ fn class_member_uniqueness_error(member: &ClassMemberDecl) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check a special class member's characteristics, and return a scope type to be used when
|
||||||
|
/// resolving that class member.
|
||||||
|
fn handle_special_members<'a, 'b>(member: &'b ClassMemberDecl) -> SloxResult<ScopeType> {
|
||||||
|
if member.kind != ClassMemberKind::Method {
|
||||||
|
return Ok(ScopeType::Method);
|
||||||
|
}
|
||||||
|
|
||||||
|
let scm = match special::SPECIAL_MEMBER_IDENTIFIERS.get(&member.fun_decl.name.lexeme as &str) {
|
||||||
|
None => return Ok(ScopeType::Method),
|
||||||
|
Some(scm) => scm,
|
||||||
|
};
|
||||||
|
if member.is_static {
|
||||||
|
return Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
|
&member.fun_decl.name,
|
||||||
|
"special members may not be static".to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let def = special::SPECIAL_MEMBERS
|
||||||
|
.get(scm)
|
||||||
|
.expect("Missing special member definition");
|
||||||
|
let n_args = member.fun_decl.params.len();
|
||||||
|
if n_args < def.min_args {
|
||||||
|
return Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
|
&member.fun_decl.name,
|
||||||
|
format!(
|
||||||
|
"this special member requires at least {} argument(s)",
|
||||||
|
def.min_args
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if n_args > def.max_args {
|
||||||
|
return Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
|
&member.fun_decl.name,
|
||||||
|
format!(
|
||||||
|
"this special member requires at most {} argument(s)",
|
||||||
|
def.max_args
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(match def.which {
|
||||||
|
special::SpecialClassMember::Init => ScopeType::Initializer,
|
||||||
|
_ => ScopeType::Method,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Process a class member's definition. A set is used to identify potential
|
/// Process a class member's definition. A set is used to identify potential
|
||||||
/// duplicates.
|
/// duplicates.
|
||||||
fn resolve_class_member<'a, 'b>(
|
fn resolve_class_member<'a, 'b>(
|
||||||
|
@ -306,13 +356,7 @@ fn resolve_class_member<'a, 'b>(
|
||||||
where
|
where
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
{
|
{
|
||||||
let is_init = member.kind == ClassMemberKind::Method
|
let scope_type = handle_special_members(member)?;
|
||||||
&& !member.is_static
|
|
||||||
&& member.fun_decl.name.lexeme == "init";
|
|
||||||
let scope_type = match is_init {
|
|
||||||
true => ScopeType::Initializer,
|
|
||||||
false => ScopeType::Method,
|
|
||||||
};
|
|
||||||
let static_key = match member.kind {
|
let static_key = match member.kind {
|
||||||
ClassMemberKind::Method => false,
|
ClassMemberKind::Method => false,
|
||||||
_ => member.is_static,
|
_ => member.is_static,
|
||||||
|
|
Loading…
Reference in a new issue