add object field getting syntax obj:field

This commit is contained in:
Mark 2025-02-07 17:50:28 +01:00
parent 3cd8dc02d2
commit e07010dcfc
9 changed files with 146 additions and 5 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mers" name = "mers"
version = "0.9.20" version = "0.9.21"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "dynamically typed but type-checked programming language" description = "dynamically typed but type-checked programming language"
@ -15,7 +15,7 @@ default = ["colored-output"]
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"] colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
[dependencies] [dependencies]
mers_lib = "0.9.20" mers_lib = "0.9.21"
# mers_lib = { path = "../mers_lib" } # mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] } clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true } colored = { version = "2.1.0", optional = true }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mers_lib" name = "mers_lib"
version = "0.9.20" version = "0.9.21"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "library to use the mers language in other projects" description = "library to use the mers language in other projects"

View File

@ -72,6 +72,7 @@ pub enum EColor {
ChainWithNonFunction, ChainWithNonFunction,
Function, Function,
FunctionArgument, FunctionArgument,
ObjectField,
InitFrom, InitFrom,
InitTo, InitTo,
AssignFrom, AssignFrom,

View File

@ -50,7 +50,7 @@ pub fn default_theme<C>(
let type_right = blue; let type_right = blue;
let type_wrong = magenta; let type_wrong = magenta;
let type_wrong_b = magenta_bright; let type_wrong_b = magenta_bright;
let function = blue_bright; // used in combination with TYPE_WRONG let function_and_field = blue_bright; // used in combination with TYPE_WRONG
let missing = cyan; let missing = cyan;
let runtime = yellow; let runtime = yellow;
let runtime_b = yellow_bright; let runtime_b = yellow_bright;
@ -93,8 +93,9 @@ pub fn default_theme<C>(
AssignTargetNonReference => type_wrong, AssignTargetNonReference => type_wrong,
Function => function, Function => function_and_field,
FunctionArgument => type_wrong, FunctionArgument => type_wrong,
ObjectField => function_and_field,
InitFrom | AssignFrom | AsTypeStatementWithTooBroadType => type_wrong, InitFrom | AssignFrom | AsTypeStatementWithTooBroadType => type_wrong,
InitTo | AssignTo | AsTypeTypeAnnotation => type_right, InitTo | AssignTo | AsTypeTypeAnnotation => type_right,

View File

@ -218,6 +218,15 @@ pub fn parse(
}); });
pos_after_first = src.get_pos(); pos_after_first = src.get_pos();
} }
} else if let Some(':') = src.peek_char() {
src.next_char();
let field = src.next_word().to_owned();
first = Box::new(program::parsed::field::Field {
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
object: first,
field,
});
pos_after_first = src.get_pos();
} else { } else {
src.set_pos(pos_after_first); src.set_pos(pos_after_first);
break; break;

View File

@ -0,0 +1,41 @@
use crate::{
data::object::ObjectFieldsMap,
errors::{CheckError, SourceRange},
info, program,
};
use super::{CompInfo, MersStatement};
/// Extracts a property with the given name from the object
#[derive(Debug)]
pub struct Field {
pub pos_in_src: SourceRange,
pub object: Box<dyn MersStatement>,
pub field: String,
}
impl MersStatement for Field {
fn has_scope(&self) -> bool {
false
}
fn compile_custom(
&self,
info: &mut info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
Ok(Box::new(program::run::field::Field {
pos_in_src: self.pos_in_src.clone(),
object: self.object.compile(info, comp)?,
field_str: self.field.clone(),
field: info.global.object_fields.get_or_add_field(&self.field),
}))
}
fn source_range(&self) -> SourceRange {
self.pos_in_src.clone()
}
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
vec![&*self.object]
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}

View File

@ -20,6 +20,8 @@ pub mod chain;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod custom_type; pub mod custom_type;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod field;
#[cfg(feature = "parse")]
pub mod function; pub mod function;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod r#if; pub mod r#if;

View File

@ -0,0 +1,85 @@
use crate::{
data::{self, object::ObjectT, Data, MersDataWInfo, MersTypeWInfo, Type},
errors::{CheckError, EColor, SourceRange},
};
use super::MersStatement;
#[derive(Debug)]
pub struct Field {
pub pos_in_src: SourceRange,
pub object: Box<dyn MersStatement>,
pub field_str: String,
pub field: usize,
}
impl MersStatement for Field {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
if init_to.is_some() {
return Err("can't init to statement type Field".to_string().into());
}
let object = self.object.check(info, init_to)?;
let mut o = Type::empty();
for t in object.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
if let Some(t) = t.get(self.field) {
o.add_all(t);
} else {
return Err(CheckError::new().msg(vec![
("can't get field ".to_owned(), None),
(self.field_str.clone(), Some(EColor::ObjectField)),
(" of object ".to_owned(), None),
(t.with_info(info).to_string(), Some(EColor::InitFrom)),
]));
}
} else {
return Err(CheckError::new().msg(vec![
("can't get field ".to_owned(), None),
(self.field_str.clone(), Some(EColor::ObjectField)),
(" of non-object type ".to_owned(), None),
(t.with_info(info).to_string(), Some(EColor::InitFrom)),
]));
}
}
Ok(o)
}
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
let object = self.object.run(info)?;
let object = object.get();
let object = object
.as_any()
.downcast_ref::<data::object::Object>()
.ok_or_else(|| {
format!(
"couldn't extract field {} from non-object value {}",
self.field_str,
object.with_info(info)
)
})?;
Ok(object
.get(self.field)
.ok_or_else(|| {
format!(
"couldn't extract field {} from object {}",
self.field_str,
object.with_info(info)
)
})?
.clone())
}
fn has_scope(&self) -> bool {
false
}
fn source_range(&self) -> SourceRange {
self.pos_in_src.clone()
}
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
vec![&*self.object]
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}

View File

@ -23,6 +23,8 @@ pub mod chain;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod custom_type; pub mod custom_type;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod field;
#[cfg(feature = "run")]
pub mod function; pub mod function;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod r#if; pub mod r#if;