mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +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;
|
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(),
|
||||||
))
|
))
|
||||||
|
@ -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,
|
||||||
|
@ -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:?}")
|
||||||
}
|
}
|
||||||
|
@ -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,17 +379,23 @@ pub mod to_runnable {
|
|||||||
o
|
o
|
||||||
}
|
}
|
||||||
SStatementEnum::Switch(switch_on, cases, force) => {
|
SStatementEnum::Switch(switch_on, cases, force) => {
|
||||||
|
if let Some(switch_on_v) = linfo.vars.get(switch_on).cloned() {
|
||||||
let mut ncases = Vec::with_capacity(cases.len());
|
let mut ncases = Vec::with_capacity(cases.len());
|
||||||
|
let og_type = linfo.vars.get(switch_on).unwrap().1.clone();
|
||||||
for case in cases {
|
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)?));
|
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
|
||||||
}
|
}
|
||||||
let switch_on = statement(switch_on, ginfo, linfo)?;
|
linfo.vars.get_mut(switch_on).unwrap().1 = og_type;
|
||||||
let switch_on_out = switch_on.out();
|
|
||||||
|
let switch_on_out = switch_on_v.1;
|
||||||
if *force {
|
if *force {
|
||||||
for val_type in switch_on_out.types.iter() {
|
for val_type in switch_on_out.types.iter() {
|
||||||
let val_type: VType = val_type.clone().into();
|
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: {
|
'force: {
|
||||||
for (case_type, _) in ncases.iter() {
|
for (case_type, _) in cases {
|
||||||
if val_type.fits_in(&case_type).is_empty() {
|
if val_type.fits_in(&case_type).is_empty() {
|
||||||
break 'force;
|
break 'force;
|
||||||
}
|
}
|
||||||
@ -395,7 +404,37 @@ pub mod to_runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RStatementEnum::Switch(switch_on, ncases)
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.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}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user