mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
add objects and object types
This commit is contained in:
parent
9c0d55788f
commit
3d1ce384d0
@ -46,16 +46,20 @@ double := x -> {
|
|||||||
// Define custom types:
|
// Define custom types:
|
||||||
// `[[MyType] TypeDefinition]`
|
// `[[MyType] TypeDefinition]`
|
||||||
|
|
||||||
[[City] (Int, Int, Int)]
|
[[City] {
|
||||||
|
population: Int
|
||||||
|
pos_x: Int
|
||||||
|
pos_y: Int
|
||||||
|
}]
|
||||||
|
|
||||||
get_coords := city -> [(Int, Int)] {
|
get_coords := city -> [(Int, Int)] {
|
||||||
// only works with values of type City
|
// only works with values of type City
|
||||||
(_, x, y) := [City] city
|
{ population: _, pos_x: x, pos_y: y } := [City] city
|
||||||
// return the coords
|
// return the coords
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
test_city := (56000, 127, -12)
|
test_city := { population: 56000, pos_x: 127, pos_y: -12 }
|
||||||
|
|
||||||
("Coords: ", test_city.get_coords).concat.println
|
("Coords: ", test_city.get_coords).concat.println
|
||||||
|
|
||||||
|
@ -19,6 +19,24 @@ pub fn assign(from: &Data, target: &Data) {
|
|||||||
for (from, target) in from.0.iter().zip(target.0.iter()) {
|
for (from, target) in from.0.iter().zip(target.0.iter()) {
|
||||||
assign(from, target);
|
assign(from, target);
|
||||||
}
|
}
|
||||||
|
} else if let (Some(from), Some(target)) = (
|
||||||
|
from.get()
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<crate::data::object::Object>(),
|
||||||
|
target
|
||||||
|
.get()
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<crate::data::object::Object>(),
|
||||||
|
) {
|
||||||
|
for (field, target) in target.0.iter() {
|
||||||
|
for (name, from) in from.0.iter() {
|
||||||
|
// TODO: do string comparison at compile-time instead!
|
||||||
|
if field == name {
|
||||||
|
assign(from, target);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("invalid assignment")
|
unreachable!("invalid assignment")
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ pub mod bool;
|
|||||||
pub mod float;
|
pub mod float;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod int;
|
pub mod int;
|
||||||
|
pub mod object;
|
||||||
pub mod reference;
|
pub mod reference;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
|
131
mers_lib/src/data/object.rs
Normal file
131
mers_lib/src/data/object.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use std::{fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use super::{Data, MersData, MersType, Type};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Object(pub Vec<(String, Data)>);
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ObjectT(pub Vec<(String, Type)>);
|
||||||
|
|
||||||
|
impl MersData for Object {
|
||||||
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
|
self == other
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn clone(&self) -> Box<dyn MersData> {
|
||||||
|
Box::new(Clone::clone(self))
|
||||||
|
}
|
||||||
|
fn as_type(&self) -> Type {
|
||||||
|
Type::new(ObjectT(
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(|(n, v)| (n.clone(), v.get().as_type()))
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn mut_any(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn to_any(self) -> Box<dyn std::any::Any> {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MersType for ObjectT {
|
||||||
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
|
other.as_any().downcast_ref::<Self>().is_some_and(|other| {
|
||||||
|
self.0.len() == other.0.len()
|
||||||
|
&& self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.zip(other.0.iter())
|
||||||
|
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_same_type_as(t2))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
|
||||||
|
target
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<Self>()
|
||||||
|
.is_some_and(|target| {
|
||||||
|
self.0.len() >= target.0.len()
|
||||||
|
&& self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.zip(target.0.iter())
|
||||||
|
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_included_in(t2))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn subtypes(&self, acc: &mut Type) {
|
||||||
|
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.0.len()));
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn mut_any(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn to_any(self) -> Box<dyn std::any::Any> {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Object {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut comma_sep = false;
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for (name, val) in self.0.iter() {
|
||||||
|
if comma_sep {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{name}: {}", val.get())?;
|
||||||
|
comma_sep = true;
|
||||||
|
}
|
||||||
|
write!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for ObjectT {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut comma_sep = false;
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for (name, t) in self.0.iter() {
|
||||||
|
if comma_sep {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{name}: {t}")?;
|
||||||
|
comma_sep = true;
|
||||||
|
}
|
||||||
|
write!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectT {
|
||||||
|
pub fn gen_subtypes_recursively(
|
||||||
|
&self,
|
||||||
|
acc: &mut Type,
|
||||||
|
types: &mut Vec<(String, Arc<dyn MersType>)>,
|
||||||
|
) {
|
||||||
|
if types.len() >= self.0.len() {
|
||||||
|
let nt = Self(
|
||||||
|
types
|
||||||
|
.iter()
|
||||||
|
.map(|(s, v)| (s.clone(), Type::newm(vec![Arc::clone(v)])))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
acc.add(Arc::new(nt));
|
||||||
|
} else {
|
||||||
|
for t in self.0[types.len()].1.subtypes_type().types {
|
||||||
|
types.push((self.0[types.len()].0.clone(), t));
|
||||||
|
self.gen_subtypes_recursively(acc, types);
|
||||||
|
types.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -180,15 +180,24 @@ impl Source {
|
|||||||
self.i += ch.len_utf8();
|
self.i += ch.len_utf8();
|
||||||
Some(ch)
|
Some(ch)
|
||||||
}
|
}
|
||||||
fn word_splitter(ch: char) -> bool {
|
fn word_splitter_no_colon(ch: char) -> bool {
|
||||||
ch.is_whitespace() || ".,;[](){}/<".contains(ch)
|
ch.is_whitespace() || ".,;[](){}/<".contains(ch)
|
||||||
}
|
}
|
||||||
|
fn word_splitter(ch: char) -> bool {
|
||||||
|
Self::word_splitter_no_colon(ch) || ch == ':'
|
||||||
|
}
|
||||||
pub fn peek_word(&self) -> &str {
|
pub fn peek_word(&self) -> &str {
|
||||||
self.src[self.i..]
|
self.src[self.i..]
|
||||||
.split(Self::word_splitter)
|
.split(Self::word_splitter)
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
}
|
}
|
||||||
|
pub fn peek_word_allow_colon(&self) -> &str {
|
||||||
|
self.src[self.i..]
|
||||||
|
.split(Self::word_splitter_no_colon)
|
||||||
|
.next()
|
||||||
|
.unwrap_or("")
|
||||||
|
}
|
||||||
pub fn next_word(&mut self) -> &str {
|
pub fn next_word(&mut self) -> &str {
|
||||||
self.end_sections();
|
self.end_sections();
|
||||||
let word = self.src[self.i..]
|
let word = self.src[self.i..]
|
||||||
@ -198,6 +207,15 @@ impl Source {
|
|||||||
self.i += word.len();
|
self.i += word.len();
|
||||||
word
|
word
|
||||||
}
|
}
|
||||||
|
pub fn next_word_allow_colon(&mut self) -> &str {
|
||||||
|
self.end_sections();
|
||||||
|
let word = self.src[self.i..]
|
||||||
|
.split(Self::word_splitter_no_colon)
|
||||||
|
.next()
|
||||||
|
.unwrap_or("");
|
||||||
|
self.i += word.len();
|
||||||
|
word
|
||||||
|
}
|
||||||
pub fn peek_line(&self) -> &str {
|
pub fn peek_line(&self) -> &str {
|
||||||
self.src[self.i..].lines().next().unwrap_or("")
|
self.src[self.i..].lines().next().unwrap_or("")
|
||||||
}
|
}
|
||||||
|
@ -35,15 +35,15 @@ pub fn parse(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
if src.peek_word() == ":=" {
|
if src.peek_word_allow_colon() == ":=" {
|
||||||
src.next_word();
|
src.next_word_allow_colon();
|
||||||
// [[name] := statement]
|
// [[name] := statement]
|
||||||
let statement = match parse(src, srca) {
|
let statement = match parse(src, srca) {
|
||||||
Ok(Some(v)) => v,
|
Ok(Some(v)) => v,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
return Err(CheckError::new()
|
return Err(CheckError::new()
|
||||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
.msg(format!("EOF after `[...]` type annotation")))
|
.msg(format!("EOF after `[[...] := ...]` type definition")))
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
@ -113,10 +113,10 @@ pub fn parse(
|
|||||||
};
|
};
|
||||||
let mut pos_after_first = src.get_pos();
|
let mut pos_after_first = src.get_pos();
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
match src.peek_word() {
|
match src.peek_word_allow_colon() {
|
||||||
":=" => {
|
":=" => {
|
||||||
let pos_in_src = src.get_pos();
|
let pos_in_src = src.get_pos();
|
||||||
src.next_word();
|
src.next_word_allow_colon();
|
||||||
let source = parse(src, srca)?.ok_or_else(|| {
|
let source = parse(src, srca)?.ok_or_else(|| {
|
||||||
CheckError::new()
|
CheckError::new()
|
||||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
@ -130,7 +130,7 @@ pub fn parse(
|
|||||||
}
|
}
|
||||||
"=" => {
|
"=" => {
|
||||||
let pos_in_src = src.get_pos();
|
let pos_in_src = src.get_pos();
|
||||||
src.next_word();
|
src.next_word_allow_colon();
|
||||||
let source = parse(src, srca)?.ok_or_else(|| {
|
let source = parse(src, srca)?.ok_or_else(|| {
|
||||||
CheckError::new()
|
CheckError::new()
|
||||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
@ -144,7 +144,7 @@ pub fn parse(
|
|||||||
}
|
}
|
||||||
"->" => {
|
"->" => {
|
||||||
let pos_in_src = src.get_pos();
|
let pos_in_src = src.get_pos();
|
||||||
src.next_word();
|
src.next_word_allow_colon();
|
||||||
let run = match parse(src, srca) {
|
let run = match parse(src, srca) {
|
||||||
Ok(Some(v)) => v,
|
Ok(Some(v)) => v,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
@ -303,8 +303,50 @@ pub fn parse_no_chain(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some('{') => {
|
Some('{') => {
|
||||||
|
// try: is this an object?
|
||||||
let pos_in_src = src.get_pos();
|
let pos_in_src = src.get_pos();
|
||||||
src.next_char();
|
src.next_char();
|
||||||
|
let pos_in_src_after_bracket = src.get_pos();
|
||||||
|
{
|
||||||
|
let mut elems = vec![];
|
||||||
|
loop {
|
||||||
|
src.skip_whitespace();
|
||||||
|
if src.peek_char() == Some('}') {
|
||||||
|
src.next_char();
|
||||||
|
return Ok(Some(Box::new(program::parsed::object::Object {
|
||||||
|
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||||
|
elems,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
let name = src.next_word().to_owned();
|
||||||
|
src.skip_whitespace();
|
||||||
|
match src.next_char() {
|
||||||
|
Some(':') => elems.push((
|
||||||
|
name,
|
||||||
|
match parse(src, srca) {
|
||||||
|
Ok(Some(v)) => v,
|
||||||
|
Ok(None) => {
|
||||||
|
return Err(CheckError::new()
|
||||||
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
|
.msg(format!("EOF after `:` in object")))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(CheckError::new()
|
||||||
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
|
.msg(format!("Error in statement after `:` in object"))
|
||||||
|
.err(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
_ => {
|
||||||
|
// not an object (or invalid syntax)
|
||||||
|
src.set_pos(pos_in_src_after_bracket);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if not an object
|
||||||
let statements = parse_multiple(src, srca, "}")?;
|
let statements = parse_multiple(src, srca, "}")?;
|
||||||
return Ok(Some(Box::new(program::parsed::block::Block {
|
return Ok(Some(Box::new(program::parsed::block::Block {
|
||||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||||
|
@ -12,6 +12,7 @@ use super::Source;
|
|||||||
pub enum ParsedType {
|
pub enum ParsedType {
|
||||||
Reference(Vec<Self>),
|
Reference(Vec<Self>),
|
||||||
Tuple(Vec<Vec<Self>>),
|
Tuple(Vec<Vec<Self>>),
|
||||||
|
Object(Vec<(String, Vec<Self>)>),
|
||||||
Type(String),
|
Type(String),
|
||||||
TypeWithInfo(String, String),
|
TypeWithInfo(String, String),
|
||||||
}
|
}
|
||||||
@ -54,6 +55,7 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
|||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
inner.push(parse_type(src, srca)?);
|
inner.push(parse_type(src, srca)?);
|
||||||
|
src.skip_whitespace();
|
||||||
match src.peek_char() {
|
match src.peek_char() {
|
||||||
Some(')') => {
|
Some(')') => {
|
||||||
src.next_char();
|
src.next_char();
|
||||||
@ -82,6 +84,42 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
|||||||
}
|
}
|
||||||
ParsedType::Tuple(inner)
|
ParsedType::Tuple(inner)
|
||||||
}
|
}
|
||||||
|
// Object
|
||||||
|
Some('{') => {
|
||||||
|
let pos_in_src = src.get_pos();
|
||||||
|
src.next_char();
|
||||||
|
src.section_begin("parse tuple's inner types".to_string());
|
||||||
|
let mut inner = vec![];
|
||||||
|
src.skip_whitespace();
|
||||||
|
if let Some('}') = src.peek_char() {
|
||||||
|
// empty object, don't even start the loop
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
src.skip_whitespace();
|
||||||
|
let field = src.next_word().to_owned();
|
||||||
|
src.skip_whitespace();
|
||||||
|
if src.next_char() != Some(':') {
|
||||||
|
return Err(CheckError::new()
|
||||||
|
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||||
|
.msg(format!("Expected colon ':' in object type")));
|
||||||
|
}
|
||||||
|
src.skip_whitespace();
|
||||||
|
inner.push((field, parse_type(src, srca)?));
|
||||||
|
src.skip_whitespace();
|
||||||
|
match src.peek_char() {
|
||||||
|
Some('}') => {
|
||||||
|
src.next_char();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Some(',') => {
|
||||||
|
src.next_char();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParsedType::Object(inner)
|
||||||
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let t = src.next_word().to_owned();
|
let t = src.next_word().to_owned();
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
@ -131,6 +169,13 @@ pub fn type_from_parsed(
|
|||||||
.map(|v| type_from_parsed(v, info))
|
.map(|v| type_from_parsed(v, info))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
)),
|
)),
|
||||||
|
ParsedType::Object(o) => Arc::new(data::object::ObjectT(
|
||||||
|
o.iter()
|
||||||
|
.map(|(s, v)| -> Result<_, CheckError> {
|
||||||
|
Ok((s.clone(), type_from_parsed(v, info)?))
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
)),
|
||||||
ParsedType::Type(name) => match info
|
ParsedType::Type(name) => match info
|
||||||
.scopes
|
.scopes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -24,6 +24,8 @@ pub mod include_mers;
|
|||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod init_to;
|
pub mod init_to;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
|
pub mod object;
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
35
mers_lib/src/program/parsed/object.rs
Normal file
35
mers_lib/src/program/parsed/object.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::{
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
|
info,
|
||||||
|
program::{self},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{CompInfo, MersStatement};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Object {
|
||||||
|
pub pos_in_src: SourceRange,
|
||||||
|
pub elems: Vec<(String, Box<dyn MersStatement>)>,
|
||||||
|
}
|
||||||
|
impl MersStatement for Object {
|
||||||
|
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::object::Object {
|
||||||
|
pos_in_src: self.pos_in_src.clone(),
|
||||||
|
elems: self
|
||||||
|
.elems
|
||||||
|
.iter()
|
||||||
|
.map(|(n, v)| -> Result<_, CheckError> { Ok((n.clone(), v.compile(info, comp)?)) })
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn source_range(&self) -> SourceRange {
|
||||||
|
self.pos_in_src.clone()
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,8 @@ pub mod function;
|
|||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod r#if;
|
pub mod r#if;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
|
pub mod object;
|
||||||
|
#[cfg(feature = "run")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
112
mers_lib/src/program/run/object.rs
Normal file
112
mers_lib/src/program/run/object.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use std::{collections::VecDeque, sync::Arc};
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
data::{self, object::ObjectT, Data, Type},
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::MersStatement;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Object {
|
||||||
|
pub pos_in_src: SourceRange,
|
||||||
|
pub elems: Vec<(String, Box<dyn MersStatement>)>,
|
||||||
|
}
|
||||||
|
impl MersStatement for Object {
|
||||||
|
fn check_custom(
|
||||||
|
&self,
|
||||||
|
info: &mut super::CheckInfo,
|
||||||
|
init_to: Option<&Type>,
|
||||||
|
) -> Result<data::Type, super::CheckError> {
|
||||||
|
let mut assign_types = if let Some(init_to) = init_to {
|
||||||
|
let print_is_part_of = init_to.types.len() > 1;
|
||||||
|
Some(
|
||||||
|
self.elems
|
||||||
|
.iter()
|
||||||
|
.map(|(field, _)| -> Result<_, CheckError> {
|
||||||
|
let mut acc = Type::empty();
|
||||||
|
for t in init_to.types.iter() {
|
||||||
|
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
|
||||||
|
let mut found = false;
|
||||||
|
for (name, assign_to) in t.0.iter() {
|
||||||
|
if name == field {
|
||||||
|
acc.add(Arc::new(assign_to.clone()));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return Err(format!(
|
||||||
|
"can't init an {} with type {}{} - field {field} not found",
|
||||||
|
"object".color(error_colors::InitTo),
|
||||||
|
t.to_string().color(error_colors::InitFrom),
|
||||||
|
if print_is_part_of {
|
||||||
|
format!(
|
||||||
|
", which is part of {}",
|
||||||
|
init_to.to_string().color(error_colors::InitFrom)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
}
|
||||||
|
).into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"can't init an {} with type {}{} - only objects can be assigned to objects",
|
||||||
|
"object".color(error_colors::InitTo),
|
||||||
|
t.to_string().color(error_colors::InitFrom),
|
||||||
|
if print_is_part_of {
|
||||||
|
format!(
|
||||||
|
", which is part of {}",
|
||||||
|
init_to.to_string().color(error_colors::InitFrom)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("")
|
||||||
|
}
|
||||||
|
).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(acc)
|
||||||
|
})
|
||||||
|
.collect::<Result<VecDeque<Type>, CheckError>>()?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Ok(Type::new(data::object::ObjectT(
|
||||||
|
self.elems
|
||||||
|
.iter()
|
||||||
|
.map(|(n, v)| -> Result<_, CheckError> {
|
||||||
|
Ok((
|
||||||
|
n.clone(),
|
||||||
|
v.check(
|
||||||
|
info,
|
||||||
|
if let Some(it) = &mut assign_types {
|
||||||
|
Some(it.pop_front().unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
.as_ref(),
|
||||||
|
)?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
|
||||||
|
Data::new(data::object::Object(
|
||||||
|
self.elems
|
||||||
|
.iter()
|
||||||
|
.map(|(n, s)| (n.clone(), s.run(info)))
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
fn has_scope(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn source_range(&self) -> SourceRange {
|
||||||
|
self.pos_in_src.clone()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user