safety commit because i want to try cargo fix

This commit is contained in:
mark 2023-04-29 16:35:25 +02:00
parent 690a4716fd
commit 8bafe58593
23 changed files with 167 additions and 167 deletions

0
iterators.mers Normal file → Executable file
View File

0
mers/src/interactive_mode.rs Normal file → Executable file
View File

0
mers/src/lib.rs Normal file → Executable file
View File

View File

@ -6,8 +6,8 @@ use crate::{
code_macro::MacroError,
code_parsed::*,
code_runnable::RScript,
global_info::GSInfo,
to_runnable::{self, GInfo, ToRunnableError},
global_info::{GlobalScriptInfo},
to_runnable::{self, ToRunnableError},
val_data::VDataEnum,
val_type::{VSingleType, VType},
},
@ -74,7 +74,7 @@ pub const PARSE_VERSION: u64 = 0;
/// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
let mut ginfo = GInfo::default();
let mut ginfo = GlobalScriptInfo::default();
let libs = parse_step_lib_paths(file)?;
let func = parse_step_interpret(file)?;
ginfo.libs = parse_step_libs_load(libs, &mut ginfo)?;
@ -135,7 +135,7 @@ impl std::fmt::Display for UnableToLoadLibrary {
}
pub fn parse_step_libs_load(
lib_cmds: Vec<Command>,
ginfo: &mut GInfo,
ginfo: &mut GlobalScriptInfo,
) -> Result<Vec<libs::Lib>, UnableToLoadLibrary> {
let mut libs = vec![];
for cmd in lib_cmds {
@ -153,7 +153,7 @@ pub fn parse_step_libs_load(
Ok(libs)
}
pub fn parse_step_compile(main_func: SFunction, ginfo: GInfo) -> Result<RScript, ToRunnableError> {
pub fn parse_step_compile(main_func: SFunction, ginfo: GlobalScriptInfo) -> Result<RScript, ToRunnableError> {
to_runnable::to_runnable(main_func, ginfo)
}
@ -177,7 +177,7 @@ pub struct ParseError {
String,
Option<(super::file::FilePosition, Option<super::file::FilePosition>)>,
)>,
info: Option<GSInfo>,
info: Option<GlobalScriptInfo>,
}
impl ParseError {
pub fn fmt_custom(
@ -246,7 +246,7 @@ impl ParseErrors {
fn fmtgs(
&self,
f: &mut std::fmt::Formatter,
info: Option<&GSInfo>,
info: Option<&GlobalScriptInfo>,
file: Option<&super::file::File>,
) -> std::fmt::Result {
match self {
@ -1150,15 +1150,16 @@ pub mod implementation {
"int" => VSingleType::Int,
"float" => VSingleType::Float,
"string" => VSingleType::String,
_ => {
return Err(ParseError {
err: ParseErrors::InvalidType(name.trim().to_string()),
location: err_start_of_single_type,
location_end: Some(*file.get_pos()),
context: vec![],
info: None,
});
}
custom => VSingleType::CustomTypeS(custom.to_owned()),
// _ => {
// return Err(ParseError {
// err: ParseErrors::InvalidType(name.trim().to_string()),
// location: err_start_of_single_type,
// location_end: Some(*file.get_pos()),
// context: vec![],
// info: None,
// });
// }
}
}
None => {

View File

@ -8,7 +8,7 @@ use crate::libs;
use super::{
code_runnable::RStatement,
global_info::GSInfo,
global_info::{GlobalScriptInfo, GSInfo},
val_data::{thread::VDataThreadEnum, VData, VDataEnum},
val_type::{VSingleType, VType},
};
@ -148,7 +148,7 @@ impl BuiltinFunction {
_ => return None,
})
}
pub fn can_take(&self, input: &Vec<VType>) -> bool {
pub fn can_take(&self, input: &Vec<VType>, info: &GlobalScriptInfo) -> bool {
match self {
Self::Assume1 => {
if input.len() >= 1 {
@ -172,7 +172,7 @@ impl BuiltinFunction {
}
if input.len() >= 2 {
if input.len() == 2 {
input[1].fits_in(&VSingleType::String.to()).is_empty()
input[1].fits_in(&VSingleType::String.to(), info).is_empty()
} else {
false
}
@ -203,7 +203,7 @@ impl BuiltinFunction {
}
if input.len() >= 2 {
if input.len() == 2 {
input[1].fits_in(&VSingleType::String.to()).is_empty()
input[1].fits_in(&VSingleType::String.to(), info).is_empty()
} else {
false
}
@ -219,7 +219,7 @@ impl BuiltinFunction {
Self::Clone => input.len() == 1 && matches!(input[0].is_reference(), Some(true)),
Self::Print | Self::Println => {
if input.len() == 1 {
input[0].fits_in(&VSingleType::String.to()).is_empty()
input[0].fits_in(&VSingleType::String.to(), info).is_empty()
} else {
false
}
@ -230,11 +230,11 @@ impl BuiltinFunction {
!input.is_empty()
&& input
.iter()
.all(|v| v.fits_in(&VSingleType::String.to()).is_empty())
.all(|v| v.fits_in(&VSingleType::String.to(), info).is_empty())
}
Self::StdinReadLine => input.is_empty(),
Self::ParseInt | Self::ParseFloat => {
input.len() == 1 && input[0].fits_in(&VSingleType::String.to()).is_empty()
input.len() == 1 && input[0].fits_in(&VSingleType::String.to(), info).is_empty()
}
Self::Run | Self::Thread => {
if input.len() >= 1 {
@ -364,7 +364,7 @@ impl BuiltinFunction {
let (vec, el) = (&input[0], &input[1]);
// if vec.is_reference().is_some_and(|v| v) { // unstable
if let Some(true) = vec.is_reference() {
if let Some(t) = vec.get_any() {
if let Some(t) = vec.get_any(info) {
el.fits_in(&t).is_empty()
} else {
false
@ -380,7 +380,7 @@ impl BuiltinFunction {
if input.len() == 3 {
let (vec, el) = (&input[0], &input[1]);
if let Some(true) = vec.is_reference() {
if let Some(t) = vec.get_any() {
if let Some(t) = vec.get_any(info) {
el.fits_in(&t).is_empty()
} else {
false
@ -397,7 +397,7 @@ impl BuiltinFunction {
let vec = &input[0];
if let Some(true) = vec.is_reference() {
// TODO! this also returns true for tuples. what should we do for tuples? should pop return (first_val rest_of_tuple) and not take a reference?
if let Some(_) = vec.get_any() {
if let Some(_) = vec.get_any(info) {
true
} else {
false
@ -414,7 +414,7 @@ impl BuiltinFunction {
let (vec, index) = (&input[0], &input[1]);
if let Some(true) = vec.is_reference() {
// TODO! same issue as in pop
if let Some(_) = vec.get_any() {
if let Some(_) = vec.get_any(info) {
if index.fits_in(&VSingleType::Int.to()).is_empty() {
true
} else {
@ -477,7 +477,7 @@ impl BuiltinFunction {
}
}
/// for invalid inputs, may panic
pub fn returns(&self, input: Vec<VType>) -> VType {
pub fn returns(&self, input: Vec<VType>, info: &GlobalScriptInfo) -> VType {
match self {
Self::Assume1 => {
let mut out = VType { types: vec![] };
@ -569,7 +569,7 @@ impl BuiltinFunction {
types: vec![
VSingleType::Tuple(vec![]),
VSingleType::Tuple(vec![v
.get_any()
.get_any(info)
.expect("cannot use get on this type")]),
],
}
@ -783,7 +783,7 @@ impl BuiltinFunction {
let val = args[0].run(vars, info);
println!(
"{} :: {} :: {}",
args[0].out().gsi(info.clone()),
args[0].out(info).gsi(info.clone()),
val.out().gsi(info.clone()),
val.gsi(info.clone())
);

0
mers/src/script/code_macro.rs Normal file → Executable file
View File

10
mers/src/script/code_parsed.rs Normal file → Executable file
View File

@ -1,6 +1,6 @@
use std::fmt::{self, Display, Formatter, Pointer};
use super::{code_macro::Macro, global_info::GSInfo, val_data::VData, val_type::VType};
use super::{code_macro::Macro, global_info::GlobalScriptInfo, val_data::VData, val_type::VType};
pub enum SStatementEnum {
Value(VData),
@ -78,7 +78,7 @@ impl SFunction {
//
impl SStatementEnum {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
match self {
Self::Value(v) => v.fmtgs(f, info),
Self::Tuple(v) => {
@ -186,7 +186,7 @@ impl Display for SStatementEnum {
}
impl SStatement {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
if let Some((opt, derefs)) = &self.output_to {
if let Some(forced_type) = &self.force_output_type {
write!(f, "{}{}::", "*".repeat(*derefs), opt)?;
@ -206,7 +206,7 @@ impl Display for SStatement {
}
impl SFunction {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
write!(f, "(")?;
for (i, (name, t)) in self.inputs.iter().enumerate() {
if i > 0 {
@ -222,7 +222,7 @@ impl SFunction {
}
impl SBlock {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
match self.statements.len() {
0 => write!(f, "{{}}"),
1 => self.statements[0].fmtgs(f, info),

53
mers/src/script/code_runnable.rs Normal file → Executable file
View File

@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex};
use super::{
builtins::BuiltinFunction,
global_info::GSInfo,
global_info::{GlobalScriptInfo, GSInfo},
to_runnable::ToRunnableError,
val_data::{VData, VDataEnum},
val_type::{VSingleType, VType},
@ -29,9 +29,9 @@ impl RBlock {
VDataEnum::Tuple(vec![]).to()
}
}
pub fn out(&self) -> VType {
pub fn out(&self, info: &GlobalScriptInfo) -> VType {
if let Some(last) = self.statements.last() {
last.out()
last.out(info)
} else {
VType {
types: vec![VSingleType::Tuple(vec![])],
@ -76,8 +76,8 @@ impl RFunction {
}
out
}
pub fn out_all(&self) -> VType {
self.block.out()
pub fn out_all(&self, info: &GlobalScriptInfo) -> VType {
self.block.out(info)
}
pub fn in_types(&self) -> &Vec<VType> {
&self.input_types
@ -109,7 +109,7 @@ impl RStatement {
out
}
}
pub fn out(&self) -> VType {
pub fn out(&self, info: &GlobalScriptInfo) -> VType {
// `a = b` evaluates to []
if self.output_to.is_some() {
return VType {
@ -119,7 +119,7 @@ impl RStatement {
if let Some(t) = &self.force_output_type {
return t.clone();
}
self.statement.out()
self.statement.out(info)
}
}
@ -283,14 +283,14 @@ impl RStatementEnum {
Self::EnumVariant(e, v) => VDataEnum::EnumVariant(*e, Box::new(v.run(vars, info))).to(),
}
}
pub fn out(&self) -> VType {
pub fn out(&self, info: &GlobalScriptInfo) -> VType {
match self {
Self::Value(v) => v.out(),
Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into(),
Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out(info)).collect()).into(),
Self::List(v) => VSingleType::List({
let mut types = VType { types: vec![] };
for t in v {
types = types | t.out();
types = types | t.out(info);
}
types
})
@ -308,21 +308,21 @@ impl RStatementEnum {
t.clone()
}
}
Self::FunctionCall(f, args) => f.out_vt(&args.iter().map(|v| v.out()).collect()),
Self::FunctionCall(f, args) => f.out_vt(&args.iter().map(|v| v.out(info)).collect()),
Self::LibFunction(.., out) => out.clone(),
Self::Block(b) => b.out(),
Self::Block(b) => b.out(info),
Self::If(_, a, b) => {
if let Some(b) = b {
a.out() | b.out()
a.out(info) | b.out(info)
} else {
a.out() | VSingleType::Tuple(vec![]).to()
a.out(info) | VSingleType::Tuple(vec![]).to()
}
}
Self::Loop(c) => c.out().matches().1,
Self::For(_, _, b) => VSingleType::Tuple(vec![]).to() | b.out().matches().1,
Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out()).collect()),
Self::Loop(c) => c.out(info).matches().1,
Self::For(_, _, b) => VSingleType::Tuple(vec![]).to() | b.out(info).matches().1,
Self::BuiltinFunction(f, args) => f.returns(args.iter().map(|rs| rs.out(info)).collect(), info),
Self::Switch(switch_on, cases) => {
let switch_on = switch_on.out().types;
let switch_on = switch_on.out(info).types;
let mut might_return_empty = switch_on.is_empty();
let mut out = VType { types: vec![] }; // if nothing is executed
for switch_on in switch_on {
@ -330,7 +330,7 @@ impl RStatementEnum {
'search: {
for (on_type, case) in cases.iter() {
if switch_on.fits_in(&on_type).is_empty() {
out = out | case.out();
out = out | case.out(info);
break 'search;
}
}
@ -345,12 +345,12 @@ impl RStatementEnum {
Self::Match(_, cases) => {
let mut out = VSingleType::Tuple(vec![]).to();
for case in cases {
out = out | case.1.out();
out = out | case.1.out(info);
}
out
}
Self::IndexFixed(st, i) => st.out().get(*i).unwrap(),
Self::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out()).to(),
Self::IndexFixed(st, i) => st.out(info).get(*i, info).unwrap(),
Self::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out(info)).to(),
}
}
pub fn to(self) -> RStatement {
@ -364,18 +364,17 @@ impl RStatementEnum {
pub struct RScript {
main: RFunction,
vars: usize,
info: GSInfo,
}
impl RScript {
pub fn new(main: RFunction, vars: usize, info: GSInfo) -> Result<Self, ToRunnableError> {
pub fn new(main: RFunction, info: GSInfo) -> Result<Self, ToRunnableError> {
if main.inputs.len() != 1 {
return Err(ToRunnableError::MainWrongInput);
}
Ok(Self { main, vars, info })
Ok(Self { main, info: info })
}
pub fn run(&self, args: Vec<String>) -> VData {
let mut vars = Vec::with_capacity(self.vars);
let mut vars = Vec::with_capacity(self.info.vars);
vars.push(am(VDataEnum::List(
VSingleType::String.into(),
args.into_iter()
@ -383,7 +382,7 @@ impl RScript {
.collect(),
)
.to()));
for _i in 1..self.vars {
for _i in 1..self.info.vars {
vars.push(am(VDataEnum::Tuple(vec![]).to()));
}
self.main.run(&vars, &self.info)

36
mers/src/script/global_info.rs Normal file → Executable file
View File

@ -2,14 +2,46 @@ use std::{collections::HashMap, sync::Arc};
use crate::libs;
use super::{val_type::VType, builtins};
pub type GSInfo = Arc<GlobalScriptInfo>;
// pub type GSMInfo = Arc<Mutex<GlobalScriptInfo>>;
pub struct GlobalScriptInfo {
pub vars: usize,
pub libs: Vec<libs::Lib>,
pub enums: HashMap<String, usize>,
pub lib_fns: HashMap<String, (usize, usize)>,
pub enum_variants: HashMap<String, usize>,
pub custom_type_names: HashMap<String, usize>,
pub custom_types: Vec<VType>,
}
impl GlobalScriptInfo {
pub fn to_arc(self) -> GSInfo {
Arc::new(self)
}
}
impl Default for GlobalScriptInfo {
fn default() -> Self {
Self {
vars: 0,
libs: vec![],
lib_fns: HashMap::new(),
enum_variants: Self::default_enum_variants(),
custom_type_names: HashMap::new(),
custom_types: vec![],
}
}
}
impl GlobalScriptInfo {
pub fn default_enum_variants() -> HashMap<String, usize> {
builtins::EVS
.iter()
.enumerate()
.map(|(i, v)| (v.to_string(), i))
.collect()
}
}

104
mers/src/script/to_runnable.rs Normal file → Executable file
View File

@ -97,46 +97,6 @@ impl Display for ToRunnableError {
}
}
// Global, shared between all
pub struct GInfo {
vars: usize,
pub libs: Vec<libs::Lib>,
pub lib_fns: HashMap<String, (usize, usize)>,
pub enum_variants: HashMap<String, usize>,
}
impl Default for GInfo {
fn default() -> Self {
Self {
vars: 0,
libs: vec![],
lib_fns: HashMap::new(),
enum_variants: Self::default_enum_variants(),
}
}
}
impl GInfo {
pub fn default_enum_variants() -> HashMap<String, usize> {
builtins::EVS
.iter()
.enumerate()
.map(|(i, v)| (v.to_string(), i))
.collect()
}
pub fn new(libs: Vec<libs::Lib>, enum_variants: HashMap<String, usize>) -> Self {
let mut lib_fns = HashMap::new();
for (libid, lib) in libs.iter().enumerate() {
for (fnid, (name, ..)) in lib.registered_fns.iter().enumerate() {
lib_fns.insert(name.to_string(), (libid, fnid));
}
}
Self {
vars: 0,
libs,
lib_fns,
enum_variants,
}
}
}
// Local, used to keep local variables separated
#[derive(Clone)]
struct LInfo {
@ -144,7 +104,7 @@ struct LInfo {
fns: HashMap<String, Arc<RFunction>>,
}
pub fn to_runnable(s: SFunction, mut ginfo: GInfo) -> Result<RScript, ToRunnableError> {
pub fn to_runnable(s: SFunction, mut ginfo: GlobalScriptInfo) -> Result<RScript, ToRunnableError> {
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
return Err(ToRunnableError::MainWrongInput);
}
@ -166,19 +126,14 @@ pub fn to_runnable(s: SFunction, mut ginfo: GInfo) -> Result<RScript, ToRunnable
)?;
Ok(RScript::new(
func,
ginfo.vars,
GlobalScriptInfo {
libs: ginfo.libs,
enums: ginfo.enum_variants,
}
.to_arc(),
ginfo.to_arc(),
)?)
}
// go over every possible known-type input for the given function, returning all possible RFunctions.
fn get_all_functions(
s: &SFunction,
ginfo: &mut GInfo,
ginfo: &mut GlobalScriptInfo,
linfo: &mut LInfo,
input_vars: &Vec<usize>,
inputs: &mut Vec<VSingleType>,
@ -197,13 +152,13 @@ fn get_all_functions(
for (varid, vartype) in s.inputs.iter().zip(inputs.iter()) {
linfo.vars.get_mut(&varid.0).unwrap().1 = vartype.clone().into();
}
out.push((inputs.clone(), block(&s.block, ginfo, linfo.clone())?.out()));
out.push((inputs.clone(), block(&s.block, ginfo, linfo.clone())?.out(ginfo)));
Ok(())
}
}
fn function(
s: &SFunction,
ginfo: &mut GInfo,
ginfo: &mut GlobalScriptInfo,
mut linfo: LInfo,
) -> Result<RFunction, ToRunnableError> {
let mut input_vars = vec![];
@ -237,7 +192,7 @@ fn function(
})
}
fn block(s: &SBlock, ginfo: &mut GInfo, mut linfo: LInfo) -> Result<RBlock, ToRunnableError> {
fn block(s: &SBlock, ginfo: &mut GlobalScriptInfo, mut linfo: LInfo) -> Result<RBlock, ToRunnableError> {
let mut statements = Vec::new();
for st in &s.statements {
statements.push(statement(st, ginfo, &mut linfo)?);
@ -245,12 +200,12 @@ fn block(s: &SBlock, ginfo: &mut GInfo, mut linfo: LInfo) -> Result<RBlock, ToRu
Ok(RBlock { statements })
}
fn stypes(t: &mut VType, ginfo: &mut GInfo) {
fn stypes(t: &mut VType, ginfo: &mut GlobalScriptInfo) {
for t in &mut t.types {
stype(t, ginfo);
}
}
fn stype(t: &mut VSingleType, ginfo: &mut GInfo) {
fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) {
match t {
VSingleType::Tuple(v) => {
for t in v {
@ -279,7 +234,7 @@ fn stype(t: &mut VSingleType, ginfo: &mut GInfo) {
}
fn statement(
s: &SStatement,
ginfo: &mut GInfo,
ginfo: &mut GlobalScriptInfo,
linfo: &mut LInfo,
) -> Result<RStatement, ToRunnableError> {
let mut statement = match &*s.statement {
@ -317,7 +272,7 @@ fn statement(
));
}
for (i, rarg) in rargs.iter().enumerate() {
let rarg = rarg.out();
let rarg = rarg.out(ginfo);
let out = rarg.fits_in(&func.input_types[i]);
if !out.is_empty() {
return Err(ToRunnableError::InvalidType {
@ -331,8 +286,8 @@ fn statement(
} else {
// TODO: type-checking for builtins
if let Some(builtin) = BuiltinFunction::get(v) {
let arg_types = rargs.iter().map(|v| v.out()).collect();
if builtin.can_take(&arg_types) {
let arg_types = rargs.iter().map(|v| v.out(ginfo)).collect();
if builtin.can_take(&arg_types, ginfo) {
RStatementEnum::BuiltinFunction(builtin, rargs)
} else {
return Err(ToRunnableError::WrongInputsForBuiltinFunction(builtin, v.to_string(), arg_types));
@ -341,12 +296,12 @@ fn statement(
// LIBRARY FUNCTION?
if let Some((libid, fnid)) = ginfo.lib_fns.get(v) {
let (_name, fn_in, fn_out) = &ginfo.libs[*libid].registered_fns[*fnid];
if fn_in.len() == rargs.len() && fn_in.iter().zip(rargs.iter()).all(|(fn_in, arg)| arg.out().fits_in(fn_in).is_empty()) {
if fn_in.len() == rargs.len() && fn_in.iter().zip(rargs.iter()).all(|(fn_in, arg)| arg.out(ginfo).fits_in(fn_in).is_empty()) {
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
} else {
// TODO! better error here
return Err(if fn_in.len() == rargs.len() {
ToRunnableError::WrongArgsForLibFunction(v.to_string(), rargs.iter().map(|v| v.out()).collect())
ToRunnableError::WrongArgsForLibFunction(v.to_string(), rargs.iter().map(|v| v.out(ginfo)).collect())
} else {
ToRunnableError::FunctionWrongArgCount(v.to_string(), fn_in.len(), rargs.len())
});
@ -375,7 +330,7 @@ fn statement(
SStatementEnum::If(c, t, e) => RStatementEnum::If(
{
let condition = statement(&c, ginfo, linfo)?;
let out = condition.out().fits_in(&VType {
let out = condition.out(ginfo).fits_in(&VType {
types: vec![VSingleType::Bool],
});
if out.is_empty() {
@ -383,7 +338,7 @@ fn statement(
} else {
return Err(ToRunnableError::InvalidType {
expected: VSingleType::Bool.into(),
found: condition.out(),
found: condition.out(ginfo),
problematic: VType { types: out },
});
}
@ -400,7 +355,7 @@ fn statement(
SStatementEnum::For(v, c, b) => {
let mut linfo = linfo.clone();
let container = statement(&c, ginfo, &mut linfo)?;
let inner = container.out().inner_types();
let inner = container.out(ginfo).inner_types();
if inner.types.is_empty() {
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
}
@ -444,7 +399,8 @@ fn statement(
types_not_covered_req_error = true;
types_not_covered = types_not_covered | {
let mut v = val_type;
fn make_readable(v: &mut VType, ginfo: &GInfo) {
/// converts the VType to one that is human-readable (changes enum from usize to String, ...)
fn make_readable(v: &mut VType, ginfo: &GlobalScriptInfo) {
for t in v.types.iter_mut() {
match t {
VSingleType::EnumVariant(i, v) => {
@ -452,18 +408,20 @@ fn statement(
make_readable(&mut v, ginfo);
*t = VSingleType::EnumVariantS(ginfo.enum_variants.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap(), v);
},
VSingleType::EnumVariantS(_, v) => make_readable(v, ginfo),
VSingleType::CustomType(i) => {
*t = VSingleType::CustomTypeS(ginfo.custom_type_names.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap());
}
VSingleType::Tuple(v) => for t in v.iter_mut() {
make_readable(t, ginfo)
}
VSingleType::List(t) => make_readable(t, ginfo),
VSingleType::List(t) | VSingleType::EnumVariantS(_, t) => make_readable(t, ginfo),
VSingleType::Reference(v) => {
let mut v = v.clone().to();
make_readable(&mut v, ginfo);
assert_eq!(v.types.len(), 1);
*t = VSingleType::Reference(Box::new(v.types.remove(0)));
}
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String | VSingleType::Function(..) | VSingleType::Thread(..) => (),
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String | VSingleType::Function(..) | VSingleType::Thread(..) | VSingleType::CustomTypeS(_) => (),
}
}
}
@ -490,7 +448,7 @@ fn statement(
let og_type = switch_on_v.1.clone(); // linfo.vars.get(match_on).unwrap().1.clone();
for case in cases {
let case_condition = statement(&case.0, ginfo, linfo)?;
let case_condition_out = case_condition.out();
let case_condition_out = case_condition.out(ginfo);
let mut refutable = false;
let mut success_output = VType { types: vec![] };
for case_type in case_condition_out.types.iter() {
@ -537,7 +495,7 @@ fn statement(
let st = statement(st, ginfo, linfo)?;
let ok = 'ok: {
let mut one = false;
for t in st.out().types {
for t in st.out(ginfo).types {
one = true;
// only if all types are indexable by i
match t {
@ -554,7 +512,7 @@ fn statement(
if ok {
RStatementEnum::IndexFixed(st, *i)
} else {
return Err(ToRunnableError::NotIndexableFixed(st.out(), *i));
return Err(ToRunnableError::NotIndexableFixed(st.out(ginfo), *i));
}
}
SStatementEnum::EnumVariant(variant, s) => RStatementEnum::EnumVariant({
@ -573,7 +531,7 @@ fn statement(
.to();
// if force_output_type is set, verify that the real output type actually fits in the forced one.
if let Some(force_opt) = &s.force_output_type {
let real_output_type = statement.out();
let real_output_type = statement.out(ginfo);
let problematic_types = real_output_type.fits_in(force_opt);
if problematic_types.is_empty() {
statement.force_output_type = Some(force_opt.clone());
@ -583,7 +541,7 @@ fn statement(
}
if let Some((opt, derefs)) = &s.output_to {
if let Some((var_id, var_out)) = linfo.vars.get(opt) {
let out = statement.out();
let out = statement.out(ginfo);
let mut var_derefd = var_out.clone();
for _ in 0..*derefs {
var_derefd = if let Some(v) = var_derefd.dereference() {
@ -612,13 +570,13 @@ fn statement(
statement.output_to = Some((*var_id, *derefs));
}
} else {
let mut out = statement.out();
let mut out = statement.out(ginfo);
for _ in 0..*derefs {
out = if let Some(v) = out.dereference() {
v
} else {
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
statement.out(),
statement.out(ginfo),
*derefs,
out,
));

View File

@ -5,7 +5,7 @@ use std::{
use super::{
code_runnable::RFunction,
global_info::GSInfo,
global_info::{GlobalScriptInfo, GSInfo},
val_type::{VSingleType, VType},
};
@ -255,7 +255,7 @@ impl VData {
}
impl VDataEnum {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
match self {
Self::Bool(true) => write!(f, "true"),
Self::Bool(false) => write!(f, "false"),
@ -290,7 +290,7 @@ impl VDataEnum {
}
Self::EnumVariant(variant, inner) => {
if let Some(name) = if let Some(info) = info {
info.enums
info.enum_variants
.iter()
.find_map(|(name, id)| if id == variant { Some(name) } else { None })
} else {
@ -312,7 +312,7 @@ impl Display for VDataEnum {
}
impl VData {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
self.data.fmtgs(f, info)
}
}

View File

@ -4,7 +4,7 @@ use std::{
ops::BitOr,
};
use super::global_info::GSInfo;
use super::global_info::{GlobalScriptInfo, GSInfo};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VType {
@ -24,20 +24,22 @@ pub enum VSingleType {
Reference(Box<Self>),
EnumVariant(usize, VType),
EnumVariantS(String, VType),
// CustomType(usize),
// CustomTypeS(String),
CustomType(usize),
CustomTypeS(String),
}
impl VSingleType {
// None => Cannot get, Some(t) => getting can return t or nothing
pub fn get(&self, i: usize) -> Option<VType> {
pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> 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()),
Self::Reference(r) => r.get(i),
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i),
Self::Reference(r) => r.get(i, gsinfo),
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i, gsinfo),
Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo),
&Self::CustomTypeS(_) => unreachable!("CustomTypeS instead of CustomType, compiler error?"),
}
}
}
@ -45,10 +47,10 @@ impl VType {
pub fn empty() -> Self {
Self { types: vec![] }
}
pub fn get(&self, i: usize) -> Option<VType> {
pub fn get(&self, i: usize, info: &GlobalScriptInfo) -> 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.
out = out | t.get(i, info)?; // if we can't use *get* on one type, we can't use it at all.
}
Some(out)
}
@ -80,15 +82,17 @@ impl VType {
}
impl VSingleType {
pub fn get_any(&self) -> Option<VType> {
pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> {
match self {
Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None,
Self::String => Some(VSingleType::String.into()),
Self::Tuple(t) => Some(t.iter().fold(VType { types: vec![] }, |a, b| a | b)),
Self::List(t) => Some(t.clone()),
Self::Reference(r) => r.get_any(),
Self::EnumVariant(_, t) => t.get_any(),
Self::Reference(r) => r.get_any(info),
Self::EnumVariant(_, t) => t.get_any(info),
Self::EnumVariantS(..) => unreachable!(),
Self::CustomType(t) => info.custom_types[*t].get_any(info),
Self::CustomTypeS(_) => unreachable!(),
}
}
pub fn is_reference(&self) -> bool {
@ -106,10 +110,10 @@ impl VSingleType {
}
}
impl VType {
pub fn get_any(&self) -> Option<VType> {
pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> {
let mut out = VType { types: vec![] };
for t in &self.types {
out = out | t.get_any()?; // if we can't use *get* on one type, we can't use it at all.
out = out | t.get_any(info)?; // if we can't use *get* on one type, we can't use it at all.
}
Some(out)
}
@ -117,11 +121,11 @@ impl VType {
impl VType {
/// Returns a vec with all types in self that aren't covered by rhs. If the returned vec is empty, self fits in rhs.
pub fn fits_in(&self, rhs: &Self) -> Vec<VSingleType> {
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> Vec<VSingleType> {
let mut no = vec![];
for t in &self.types {
// if t doesnt fit in any of rhs's types
if !rhs.types.iter().any(|r| t.fits_in(r)) {
if !rhs.types.iter().any(|r| t.fits_in(r, info)) {
no.push(t.clone())
}
}
@ -223,6 +227,7 @@ impl VSingleType {
v => v.to(),
}
}
/// converts all Self::EnumVariantS to Self::EnumVariant
pub fn enum_variants(&mut self, enum_variants: &mut HashMap<String, usize>) {
match self {
Self::Bool | Self::Int | Self::Float | Self::String => (),
@ -254,15 +259,20 @@ impl VSingleType {
v.enum_variants(enum_variants);
*self = Self::EnumVariant(e, v.clone());
}
Self::CustomType(_) | Self::CustomTypeS(_) => (),
}
}
pub fn fits_in(&self, rhs: &Self) -> bool {
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool {
match (self, rhs) {
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b),
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b, info),
(Self::Reference(_), _) | (_, Self::Reference(_)) => false,
(Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => {
*v1 == *v2 && t1.fits_in(&t2).is_empty()
}
*v1 == *v2 && t1.fits_in(&t2, info).is_empty()
},
(Self::CustomType(a), b) => info.custom_types[*a].fits_in(&b.clone().to(), info).is_empty(),
(a, Self::CustomType(b)) => a.clone().to().fits_in(&info.custom_types[*b], info).is_empty(),
(Self::CustomType(a), Self::CustomType(b)) => info.custom_types[*a].fits_in(&info.custom_types[*b], info).is_empty(),
(Self::CustomTypeS(_), _) | (_, Self::CustomTypeS(_)) => unreachable!(),
(Self::EnumVariant(..), _) | (_, Self::EnumVariant(..)) => false,
(Self::EnumVariantS(..), _) | (_, Self::EnumVariantS(..)) => unreachable!(),
(Self::Bool, Self::Bool)
@ -272,19 +282,19 @@ impl VSingleType {
(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())
a.iter().zip(b.iter()).all(|(a, b)| a.fits_in(b, info).is_empty())
} else {
false
}
}
(Self::Tuple(_), _) => false,
(Self::List(a), Self::List(b)) => a.fits_in(b).is_empty(),
(Self::List(a), Self::List(b)) => a.fits_in(b, info).is_empty(),
(Self::List(_), _) => false,
(Self::Function(a), Self::Function(b)) => 'func_out: {
for a in a {
'search: {
for b in b {
if a.1.fits_in(&b.1).is_empty()
if a.1.fits_in(&b.1, info).is_empty()
&& a.0.iter().zip(b.0.iter()).all(|(a, b)| *a == *b)
{
break 'search;
@ -296,7 +306,7 @@ impl VSingleType {
true
}
(Self::Function(..), _) => false,
(Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(),
(Self::Thread(a), Self::Thread(b)) => a.fits_in(b, info).is_empty(),
(Self::Thread(..), _) => false,
}
}
@ -323,7 +333,7 @@ impl VType {
}
impl VSingleType {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
match self {
Self::Bool => write!(f, "bool"),
Self::Int => write!(f, "int"),
@ -368,7 +378,7 @@ impl VSingleType {
}
Self::EnumVariant(variant, inner) => {
if let Some(name) = if let Some(info) = info {
info.enums
info.enum_variants
.iter()
.find_map(|(name, id)| if id == variant { Some(name) } else { None })
} else {
@ -396,7 +406,7 @@ impl Display for VSingleType {
}
impl VType {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GSInfo>) -> fmt::Result {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result {
for (i, t) in self.types.iter().enumerate() {
if i > 0 {
write!(f, "/")?;

0
mers/src/tutor/base_comments.rs Normal file → Executable file
View File

0
mers/src/tutor/base_functions.rs Normal file → Executable file
View File

0
mers/src/tutor/base_return.rs Normal file → Executable file
View File

0
mers/src/tutor/base_types.rs Normal file → Executable file
View File

0
mers/src/tutor/base_values.rs Normal file → Executable file
View File

0
mers/src/tutor/base_variables.rs Normal file → Executable file
View File

0
mers/src/tutor/error_handling.rs Normal file → Executable file
View File

0
mers/src/tutor/menu.rs Normal file → Executable file
View File

0
mers/src/tutor/mod.rs Normal file → Executable file
View File

0
mersrandr.mers Normal file → Executable file
View File

0
my_macro.mers Normal file → Executable file
View File