diff --git a/mers/Cargo.toml b/mers/Cargo.toml index e0de380..73908a1 100644 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers" -version = "0.9.20" +version = "0.9.21" edition = "2021" license = "MIT OR Apache-2.0" 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"] [dependencies] -mers_lib = "0.9.20" +mers_lib = "0.9.21" # mers_lib = { path = "../mers_lib" } clap = { version = "4.3.19", features = ["derive"] } colored = { version = "2.1.0", optional = true } diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index 9f8040f..9150e4c 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers_lib" -version = "0.9.20" +version = "0.9.21" edition = "2021" license = "MIT OR Apache-2.0" description = "library to use the mers language in other projects" diff --git a/mers_lib/src/errors/mod.rs b/mers_lib/src/errors/mod.rs index 2c63331..affd25a 100644 --- a/mers_lib/src/errors/mod.rs +++ b/mers_lib/src/errors/mod.rs @@ -72,6 +72,7 @@ pub enum EColor { ChainWithNonFunction, Function, FunctionArgument, + ObjectField, InitFrom, InitTo, AssignFrom, diff --git a/mers_lib/src/errors/themes.rs b/mers_lib/src/errors/themes.rs index ca65d2d..408738b 100644 --- a/mers_lib/src/errors/themes.rs +++ b/mers_lib/src/errors/themes.rs @@ -50,7 +50,7 @@ pub fn default_theme( let type_right = blue; let type_wrong = magenta; 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 runtime = yellow; let runtime_b = yellow_bright; @@ -93,8 +93,9 @@ pub fn default_theme( AssignTargetNonReference => type_wrong, - Function => function, + Function => function_and_field, FunctionArgument => type_wrong, + ObjectField => function_and_field, InitFrom | AssignFrom | AsTypeStatementWithTooBroadType => type_wrong, InitTo | AssignTo | AsTypeTypeAnnotation => type_right, diff --git a/mers_lib/src/parsing/statements.rs b/mers_lib/src/parsing/statements.rs index 1307869..495a9df 100755 --- a/mers_lib/src/parsing/statements.rs +++ b/mers_lib/src/parsing/statements.rs @@ -218,6 +218,15 @@ pub fn parse( }); 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 { src.set_pos(pos_after_first); break; diff --git a/mers_lib/src/program/parsed/field.rs b/mers_lib/src/program/parsed/field.rs new file mode 100644 index 0000000..481fa47 --- /dev/null +++ b/mers_lib/src/program/parsed/field.rs @@ -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, + pub field: String, +} +impl MersStatement for Field { + fn has_scope(&self) -> bool { + false + } + fn compile_custom( + &self, + info: &mut info::Info, + comp: CompInfo, + ) -> Result, 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 + } +} diff --git a/mers_lib/src/program/parsed/mod.rs b/mers_lib/src/program/parsed/mod.rs index 48cf6e9..bfb54ff 100755 --- a/mers_lib/src/program/parsed/mod.rs +++ b/mers_lib/src/program/parsed/mod.rs @@ -20,6 +20,8 @@ pub mod chain; #[cfg(feature = "parse")] pub mod custom_type; #[cfg(feature = "parse")] +pub mod field; +#[cfg(feature = "parse")] pub mod function; #[cfg(feature = "parse")] pub mod r#if; diff --git a/mers_lib/src/program/run/field.rs b/mers_lib/src/program/run/field.rs new file mode 100644 index 0000000..da68b06 --- /dev/null +++ b/mers_lib/src/program/run/field.rs @@ -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, + pub field_str: String, + pub field: usize, +} +impl MersStatement for Field { + fn check_custom( + &self, + info: &mut super::CheckInfo, + init_to: Option<&Type>, + ) -> Result { + 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::() { + 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 { + let object = self.object.run(info)?; + let object = object.get(); + let object = object + .as_any() + .downcast_ref::() + .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 + } +} diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 0a6a149..fd54a8b 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -23,6 +23,8 @@ pub mod chain; #[cfg(feature = "run")] pub mod custom_type; #[cfg(feature = "run")] +pub mod field; +#[cfg(feature = "run")] pub mod function; #[cfg(feature = "run")] pub mod r#if;