- fixed a bug with t.fits_in(rhs) regarding inner types

- added //...\n and /*...*/ comment syntax
- added tuple.n indexing, where n is an int <= the tuples length (this is checked before the script runs)
This commit is contained in:
Dummi26 2023-03-12 15:42:19 +01:00
parent 15b78dc0b6
commit a4fbb8dd97
5 changed files with 186 additions and 25 deletions

View File

@ -6,8 +6,21 @@ pub(crate) mod parse;
pub(crate) mod script; pub(crate) mod script;
fn main() { fn main() {
let str1: VType = VSingleType::String.into(); let val: VType = VSingleType::Tuple(vec![
assert!(str1.fits_in(&VSingleType::String.into()).is_empty()); VSingleType::Int.into(),
VSingleType::String.into(),
VSingleType::String.into(),
])
.into();
let case: VType = VSingleType::Tuple(vec![
VType {
types: vec![VSingleType::Tuple(vec![]).into(), VSingleType::Int.into()],
},
VSingleType::String.into(),
VSingleType::String.into(),
])
.into();
assert!(val.fits_in(&case).is_empty());
let script = parse::parse::parse(&mut parse::file::File::new( let script = parse::parse::parse(&mut parse::file::File::new(
std::fs::read_to_string("/tmp/script.txt").unwrap(), std::fs::read_to_string("/tmp/script.txt").unwrap(),
)) ))

View File

@ -25,6 +25,41 @@ impl Display for FilePosition {
impl File { impl File {
pub fn new(data: String) -> Self { pub fn new(data: String) -> Self {
let mut chs = data.chars();
let mut data = String::with_capacity(data.len());
loop {
match chs.next() {
Some('/') => match chs.next() {
Some('/') => loop {
match chs.next() {
Some('\n') | None => break,
_ => (),
}
},
Some('*') => loop {
match chs.next() {
Some('*') => {
if let Some('/') = chs.next() {
break;
}
}
None => break,
_ => (),
}
},
Some(ch) => {
data.push('/');
data.push(ch);
}
None => {
data.push('/');
break;
}
},
Some(ch) => data.push(ch),
None => break,
}
}
let chars = data.char_indices().collect(); let chars = data.char_indices().collect();
Self { Self {
data, data,

View File

@ -271,12 +271,7 @@ fn parse_statement_adv(
} }
cases.push((parse_type(file)?, parse_statement(file)?)); cases.push((parse_type(file)?, parse_statement(file)?));
} }
break SStatementEnum::Switch( break SStatementEnum::Switch(switch_on_what, cases, force).into();
SStatementEnum::Variable(switch_on_what).into(),
cases,
force,
)
.into();
} }
"true" => { "true" => {
break SStatementEnum::Value(VDataEnum::Bool(true).to()).into() break SStatementEnum::Value(VDataEnum::Bool(true).to()).into()
@ -332,6 +327,10 @@ fn parse_statement_adv(
let args = [out].into_iter().chain(args.into_iter()).collect(); let args = [out].into_iter().chain(args.into_iter()).collect();
SStatementEnum::FunctionCall(func, args).into() SStatementEnum::FunctionCall(func, args).into()
} }
SStatementEnum::Value(vd) => match vd.data {
VDataEnum::Int(i) => SStatementEnum::IndexFixed(out, i as _).into(),
_ => todo!("fixed-indexing not available with this type."),
},
other => { other => {
todo!("Wrapping in this type isn't implemented (yet?). Type: {other:?}") todo!("Wrapping in this type isn't implemented (yet?). Type: {other:?}")
} }

View File

@ -66,8 +66,9 @@ pub enum SStatementEnum {
If(SStatement, SStatement, Option<SStatement>), If(SStatement, SStatement, Option<SStatement>),
While(SStatement), While(SStatement),
For(String, SStatement, SStatement), For(String, SStatement, SStatement),
Switch(SStatement, Vec<(VType, SStatement)>, bool), Switch(String, Vec<(VType, SStatement)>, bool),
// Match(???), // Match(???),
IndexFixed(SStatement, usize),
} }
impl Into<SStatement> for SStatementEnum { impl Into<SStatement> for SStatementEnum {
fn into(self) -> SStatement { fn into(self) -> SStatement {
@ -112,6 +113,7 @@ pub mod to_runnable {
}, },
InvalidTypeForWhileLoop(VType), InvalidTypeForWhileLoop(VType),
CaseForceButTypeNotCovered(VType), CaseForceButTypeNotCovered(VType),
NotIndexableFixed(VType, usize),
} }
impl Debug for ToRunnableError { impl Debug for ToRunnableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -137,6 +139,7 @@ pub mod to_runnable {
} }
Self::InvalidTypeForWhileLoop(v) => write!(f, "Invalid type: Expected bool or Tuples of length 0 or 1 as return types for the while loop, but found {v:?} instead."), Self::InvalidTypeForWhileLoop(v) => write!(f, "Invalid type: Expected bool or Tuples of length 0 or 1 as return types for the while loop, but found {v:?} instead."),
Self::CaseForceButTypeNotCovered(v) => write!(f, "Switch! statement, but not all types covered. Types to cover: {v}"), Self::CaseForceButTypeNotCovered(v) => write!(f, "Switch! statement, but not all types covered. Types to cover: {v}"),
Self::NotIndexableFixed(t, i) => write!(f, "Cannot use fixed-index {i} on type {t}."),
} }
} }
} }
@ -376,26 +379,62 @@ pub mod to_runnable {
o o
} }
SStatementEnum::Switch(switch_on, cases, force) => { SStatementEnum::Switch(switch_on, cases, force) => {
let mut ncases = Vec::with_capacity(cases.len()); if let Some(switch_on_v) = linfo.vars.get(switch_on).cloned() {
for case in cases { let mut ncases = Vec::with_capacity(cases.len());
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?)); let og_type = linfo.vars.get(switch_on).unwrap().1.clone();
} for case in cases {
let switch_on = statement(switch_on, ginfo, linfo)?; linfo.vars.get_mut(switch_on).unwrap().1 = case.0.clone();
let switch_on_out = switch_on.out(); ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
if *force { }
for val_type in switch_on_out.types.iter() { linfo.vars.get_mut(switch_on).unwrap().1 = og_type;
let val_type: VType = val_type.clone().into();
'force: { let switch_on_out = switch_on_v.1;
for (case_type, _) in ncases.iter() { if *force {
if val_type.fits_in(&case_type).is_empty() { for val_type in switch_on_out.types.iter() {
break 'force; let val_type: VType = val_type.clone().into();
let mut linf2 = linfo.clone();
linf2.vars.get_mut(switch_on).unwrap().1 = val_type.clone();
'force: {
for (case_type, _) in cases {
if val_type.fits_in(&case_type).is_empty() {
break 'force;
}
} }
return Err(ToRunnableError::CaseForceButTypeNotCovered(val_type));
} }
return Err(ToRunnableError::CaseForceButTypeNotCovered(val_type));
} }
} }
RStatementEnum::Switch(
RStatementEnum::Variable(switch_on_v.0, switch_on_out).to(),
ncases,
)
} else {
return Err(ToRunnableError::UseOfUndefinedVariable(switch_on.clone()));
}
}
SStatementEnum::IndexFixed(st, i) => {
let st = statement(st, ginfo, linfo)?;
let ok = 'ok: {
let mut one = false;
for t in st.out().types {
one = true;
// only if all types are indexable by i
match t {
VSingleType::Tuple(v) => {
if v.len() <= *i {
break 'ok false;
}
}
_ => break 'ok false,
}
}
one
};
if ok {
RStatementEnum::IndexFixed(st, *i)
} else {
return Err(ToRunnableError::NotIndexableFixed(st.out(), *i));
} }
RStatementEnum::Switch(switch_on, ncases)
} }
} }
.to(); .to();
@ -523,6 +562,7 @@ pub enum RStatementEnum {
While(RStatement), While(RStatement),
For(usize, RStatement, RStatement), For(usize, RStatement, RStatement),
Switch(RStatement, Vec<(VType, RStatement)>), Switch(RStatement, Vec<(VType, RStatement)>),
IndexFixed(RStatement, usize),
} }
impl RStatementEnum { impl RStatementEnum {
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData { pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
@ -620,6 +660,7 @@ impl RStatementEnum {
} }
out out
} }
Self::IndexFixed(st, i) => st.run(vars).get(*i).unwrap(),
} }
} }
pub fn out(&self) -> VType { pub fn out(&self) -> VType {
@ -657,6 +698,7 @@ impl RStatementEnum {
} }
out out
} }
Self::IndexFixed(st, i) => st.out().get(*i).unwrap(),
} }
} }
pub fn to(self) -> RStatement { pub fn to(self) -> RStatement {
@ -820,6 +862,7 @@ impl Display for SStatementEnum {
} }
write!(f, "}}") write!(f, "}}")
} }
SStatementEnum::IndexFixed(st, i) => write!(f, "{st}.{i}"),
} }
} }
} }

View File

@ -34,6 +34,9 @@ impl VData {
VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()),
} }
} }
pub fn get(&self, i: usize) -> Option<Self> {
self.data.get(i)
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -118,6 +121,45 @@ impl VDataEnum {
} }
} }
// get()
impl VDataEnum {
pub fn get(&self, i: usize) -> Option<VData> {
match self {
Self::Bool(..)
| Self::Int(..)
| Self::Float(..)
| Self::Function(..)
| Self::Thread(..) => None,
Self::String(s) => match s.chars().nth(i) {
// Slow!
Some(ch) => Some(Self::String(format!("{ch}")).to()),
None => None,
},
Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(),
}
}
}
impl VSingleType {
// None => Cannot get, Some(t) => getting can return t or nothing
pub fn get(&self, i: usize) -> Option<VType> {
match self {
Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None,
Self::String => Some(VSingleType::String.into()),
Self::Tuple(t) => t.get(i).cloned(),
Self::List(t) => Some(t.clone()),
}
}
}
impl VType {
pub fn get(&self, i: usize) -> Option<VType> {
let mut out = VType { types: vec![] };
for t in &self.types {
out = out | t.get(i)?; // if we can't use *get* on one type, we can't use it at all.
}
Some(out)
}
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct VType { pub struct VType {
pub types: Vec<VSingleType>, pub types: Vec<VSingleType>,
@ -127,7 +169,8 @@ impl VType {
pub fn fits_in(&self, rhs: &Self) -> Vec<VSingleType> { pub fn fits_in(&self, rhs: &Self) -> Vec<VSingleType> {
let mut no = vec![]; let mut no = vec![];
for t in &self.types { for t in &self.types {
if !rhs.types.contains(t) { // if t doesnt fit in any of rhs's types
if !rhs.types.iter().any(|r| t.fits_in(r)) {
no.push(t.clone()) no.push(t.clone())
} }
} }
@ -187,6 +230,34 @@ impl VSingleType {
_ => vec![], _ => vec![],
} }
} }
pub fn fits_in(&self, rhs: &Self) -> bool {
match (self, rhs) {
(Self::Bool, Self::Bool)
| (Self::Int, Self::Int)
| (Self::Float, Self::Float)
| (Self::String, Self::String) => true,
(Self::Bool | Self::Int | Self::Float | Self::String, _) => false,
(Self::Tuple(a), Self::Tuple(b)) => {
if a.len() == b.len() {
a.iter().zip(b.iter()).all(|(a, b)| a.fits_in(b).is_empty())
} else {
false
}
}
(Self::Tuple(_), _) => false,
(Self::List(a), Self::List(b)) => a.fits_in(b).is_empty(),
(Self::List(_), _) => false,
(Self::Function(ai, ao), Self::Function(bi, bo)) => {
ai.iter()
.zip(bi.iter())
.all(|(a, b)| a.fits_in(b).is_empty())
&& ao.fits_in(bo).is_empty()
}
(Self::Function(..), _) => false,
(Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(),
(Self::Thread(..), _) => false,
}
}
} }
impl Into<VType> for VSingleType { impl Into<VType> for VSingleType {