mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 05:43:53 +01:00
- 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:
parent
15b78dc0b6
commit
a4fbb8dd97
17
src/main.rs
17
src/main.rs
@ -6,8 +6,21 @@ pub(crate) mod parse;
|
||||
pub(crate) mod script;
|
||||
|
||||
fn main() {
|
||||
let str1: VType = VSingleType::String.into();
|
||||
assert!(str1.fits_in(&VSingleType::String.into()).is_empty());
|
||||
let val: VType = VSingleType::Tuple(vec![
|
||||
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(
|
||||
std::fs::read_to_string("/tmp/script.txt").unwrap(),
|
||||
))
|
||||
|
@ -25,6 +25,41 @@ impl Display for FilePosition {
|
||||
|
||||
impl File {
|
||||
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();
|
||||
Self {
|
||||
data,
|
||||
|
@ -271,12 +271,7 @@ fn parse_statement_adv(
|
||||
}
|
||||
cases.push((parse_type(file)?, parse_statement(file)?));
|
||||
}
|
||||
break SStatementEnum::Switch(
|
||||
SStatementEnum::Variable(switch_on_what).into(),
|
||||
cases,
|
||||
force,
|
||||
)
|
||||
.into();
|
||||
break SStatementEnum::Switch(switch_on_what, cases, force).into();
|
||||
}
|
||||
"true" => {
|
||||
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();
|
||||
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 => {
|
||||
todo!("Wrapping in this type isn't implemented (yet?). Type: {other:?}")
|
||||
}
|
||||
|
@ -66,8 +66,9 @@ pub enum SStatementEnum {
|
||||
If(SStatement, SStatement, Option<SStatement>),
|
||||
While(SStatement),
|
||||
For(String, SStatement, SStatement),
|
||||
Switch(SStatement, Vec<(VType, SStatement)>, bool),
|
||||
Switch(String, Vec<(VType, SStatement)>, bool),
|
||||
// Match(???),
|
||||
IndexFixed(SStatement, usize),
|
||||
}
|
||||
impl Into<SStatement> for SStatementEnum {
|
||||
fn into(self) -> SStatement {
|
||||
@ -112,6 +113,7 @@ pub mod to_runnable {
|
||||
},
|
||||
InvalidTypeForWhileLoop(VType),
|
||||
CaseForceButTypeNotCovered(VType),
|
||||
NotIndexableFixed(VType, usize),
|
||||
}
|
||||
impl Debug for ToRunnableError {
|
||||
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::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
|
||||
}
|
||||
SStatementEnum::Switch(switch_on, cases, force) => {
|
||||
let mut ncases = Vec::with_capacity(cases.len());
|
||||
for case in cases {
|
||||
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
|
||||
}
|
||||
let switch_on = statement(switch_on, ginfo, linfo)?;
|
||||
let switch_on_out = switch_on.out();
|
||||
if *force {
|
||||
for val_type in switch_on_out.types.iter() {
|
||||
let val_type: VType = val_type.clone().into();
|
||||
'force: {
|
||||
for (case_type, _) in ncases.iter() {
|
||||
if val_type.fits_in(&case_type).is_empty() {
|
||||
break 'force;
|
||||
if let Some(switch_on_v) = linfo.vars.get(switch_on).cloned() {
|
||||
let mut ncases = Vec::with_capacity(cases.len());
|
||||
let og_type = linfo.vars.get(switch_on).unwrap().1.clone();
|
||||
for case in cases {
|
||||
linfo.vars.get_mut(switch_on).unwrap().1 = case.0.clone();
|
||||
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
|
||||
}
|
||||
linfo.vars.get_mut(switch_on).unwrap().1 = og_type;
|
||||
|
||||
let switch_on_out = switch_on_v.1;
|
||||
if *force {
|
||||
for val_type in switch_on_out.types.iter() {
|
||||
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();
|
||||
@ -523,6 +562,7 @@ pub enum RStatementEnum {
|
||||
While(RStatement),
|
||||
For(usize, RStatement, RStatement),
|
||||
Switch(RStatement, Vec<(VType, RStatement)>),
|
||||
IndexFixed(RStatement, usize),
|
||||
}
|
||||
impl RStatementEnum {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
|
||||
@ -620,6 +660,7 @@ impl RStatementEnum {
|
||||
}
|
||||
out
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.run(vars).get(*i).unwrap(),
|
||||
}
|
||||
}
|
||||
pub fn out(&self) -> VType {
|
||||
@ -657,6 +698,7 @@ impl RStatementEnum {
|
||||
}
|
||||
out
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.out().get(*i).unwrap(),
|
||||
}
|
||||
}
|
||||
pub fn to(self) -> RStatement {
|
||||
@ -820,6 +862,7 @@ impl Display for SStatementEnum {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
SStatementEnum::IndexFixed(st, i) => write!(f, "{st}.{i}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ impl VData {
|
||||
VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()),
|
||||
}
|
||||
}
|
||||
pub fn get(&self, i: usize) -> Option<Self> {
|
||||
self.data.get(i)
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub struct VType {
|
||||
pub types: Vec<VSingleType>,
|
||||
@ -127,7 +169,8 @@ impl VType {
|
||||
pub fn fits_in(&self, rhs: &Self) -> Vec<VSingleType> {
|
||||
let mut no = vec![];
|
||||
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())
|
||||
}
|
||||
}
|
||||
@ -187,6 +230,34 @@ impl VSingleType {
|
||||
_ => 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user