This commit is contained in:
Jeff 2024-06-26 17:35:30 -04:00
parent 29bbcb019d
commit fe0bb0a0b5
5 changed files with 94 additions and 48 deletions

View File

@ -66,10 +66,10 @@ impl AbstractNode for Block {
impl Display for Block { impl Display for Block {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{{")?; write!(f, "{{ ")?;
for statement in &self.statements { for statement in &self.statements {
write!(f, "{statement}")?; write!(f, "{statement} ")?;
} }
write!(f, "}}") write!(f, "}}")

View File

@ -7,6 +7,7 @@ use crate::{
abstract_tree::Type, abstract_tree::Type,
error::{PoisonError, ValidationError}, error::{PoisonError, ValidationError},
identifier::Identifier, identifier::Identifier,
value::ValueInner,
Value, Value,
}; };
@ -43,22 +44,14 @@ impl Context {
Ok(()) Ok(())
} }
pub fn contains(&self, identifier: &Identifier) -> Result<bool, PoisonError> { pub fn contains(&self, identifier: &Identifier) -> Result<bool, ValidationError> {
log::trace!("Checking that {identifier} exists."); log::trace!("Checking that {identifier} exists");
let data = self.data.read()?; Ok(self.get_type(identifier)?.is_some())
if data.variables.contains_key(identifier) {
Ok(true)
} else if let Some(parent) = &data.parent {
parent.contains(identifier)
} else {
Ok(false)
}
} }
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
log::trace!("Getting {identifier}'s type."); log::trace!("Getting {identifier}'s type");
let data = self.data.read()?; let data = self.data.read()?;
@ -68,16 +61,23 @@ impl Context {
VariableData::Value(value) => value.r#type(self)?, VariableData::Value(value) => value.r#type(self)?,
}; };
Ok(Some(r#type.clone())) return Ok(Some(r#type.clone()));
} else if let Some(parent) = &data.parent { } else if let Some(parent) = &data.parent {
parent.get_type(identifier) if let Some(r#type) = parent.get_type(identifier)? {
} else { match r#type {
Ok(None) Type::Enum { .. } | Type::Function { .. } | Type::Structure { .. } => {
return Ok(Some(r#type))
}
_ => {}
}
}
} }
Ok(None)
} }
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> { pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
log::trace!("Using {identifier}'s value."); log::trace!("Using {identifier}'s value");
let data = self.data.read()?; let data = self.data.read()?;
@ -85,30 +85,44 @@ impl Context {
usage_data.inner().write()?.actual += 1; usage_data.inner().write()?.actual += 1;
*self.is_clean.write()? = false; *self.is_clean.write()? = false;
Ok(Some(value.clone())) return Ok(Some(value.clone()));
} else if let Some(parent) = &data.parent { } else if let Some(parent) = &data.parent {
parent.get_value(identifier) if let Some(value) = parent.get_value(identifier)? {
} else { match value.inner().as_ref() {
Ok(None) ValueInner::EnumInstance { .. }
| ValueInner::Function(_)
| ValueInner::Structure { .. } => return Ok(Some(value)),
_ => {}
}
}
} }
Ok(None)
} }
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> { pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
log::trace!("Getting {identifier}'s value."); log::trace!("Getting {identifier}'s value");
let data = self.data.read()?; let data = self.data.read()?;
if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) { if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) {
Ok(Some(value.clone())) return Ok(Some(value.clone()));
} else if let Some(parent) = &data.parent { } else if let Some(parent) = &data.parent {
parent.get_value(identifier) if let Some(value) = parent.get_value(identifier)? {
} else { match value.inner().as_ref() {
Ok(None) ValueInner::EnumInstance { .. }
| ValueInner::Function(_)
| ValueInner::Structure { .. } => return Ok(Some(value)),
_ => {}
}
}
} }
Ok(None)
} }
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> { pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to type {}.", r#type); log::debug!("Setting {identifier} to type {}", r#type);
self.data self.data
.write()? .write()?
@ -119,7 +133,7 @@ impl Context {
} }
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> { pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to value {value}."); log::debug!("Setting {identifier} to value {value}");
let mut data = self.data.write()?; let mut data = self.data.write()?;
let usage_data = data let usage_data = data
@ -138,7 +152,7 @@ impl Context {
let data = self.data.read()?; let data = self.data.read()?;
if let Some((_, usage_data)) = data.variables.get(identifier) { if let Some((_, usage_data)) = data.variables.get(identifier) {
log::trace!("Adding expected use for variable {identifier}."); log::trace!("Adding expected use for variable {identifier}");
usage_data.inner().write()?.expected += 1; usage_data.inner().write()?.expected += 1;
@ -155,22 +169,22 @@ impl Context {
return Ok(()); return Ok(());
} }
// self.data.write()?.variables.retain( self.data.write()?.variables.retain(
// |identifier, (value_data, usage_data)| match value_data { |identifier, (value_data, usage_data)| match value_data {
// VariableData::Type(_) => true, VariableData::Type(_) => true,
// VariableData::Value(_) => { VariableData::Value(_) => {
// let usage = usage_data.inner().read().unwrap(); let usage = usage_data.inner().read().unwrap();
// if usage.actual < usage.expected { if usage.actual < usage.expected {
// true true
// } else { } else {
// log::trace!("Removing {identifier}."); log::trace!("Removing {identifier}");
// false false
// } }
// } }
// }, },
// ); );
*self.is_clean.write()? = true; *self.is_clean.write()? = true;

View File

@ -407,7 +407,7 @@ pub fn parser<'src>(
if !allow_built_ins { if !allow_built_ins {
emitter.emit(Rich::custom( emitter.emit(Rich::custom(
state.span(), state.span(),
"Built-in function calls can only be used by the standard library.", "Built-in functions can only be used by the standard library.",
)) ))
} }

View File

@ -214,10 +214,10 @@ impl Display for Value {
write!(f, ")")?; write!(f, ")")?;
if let Some(return_type) = return_type { if let Some(return_type) = return_type {
write!(f, "-> {return_type}")? write!(f, " -> {return_type}")?
} }
write!(f, " {{ {body} }}") write!(f, " {body}")
} }
ValueInner::Structure { name, fields } => { ValueInner::Structure { name, fields } => {
write!(f, "{}\n{{", name.node)?; write!(f, "{}\n{{", name.node)?;

View File

@ -49,3 +49,35 @@ fn function_return_type_error() {
}] }]
); );
} }
#[test]
fn scope() {
assert_eq!(
interpret(
"test",
"
x = 1
foo = fn () -> int {
x
1
}
foo()
"
)
.unwrap_err()
.errors(),
&vec![DustError::Validation {
error: ValidationError::TypeCheck {
conflict: TypeConflict {
actual: Type::String,
expected: Type::Integer
},
actual_position: (66, 71).into(),
expected_position: Some((60, 63).into())
},
position: (55, 71).into()
}]
);
}