mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
temporarily made cloning actually clone, giving up on CopyOnWrite for now because I kept finding tiny bugs. This might harm performance, but overall performance was bad and will still be bad so who even cares, at least everything kindof works now.
This commit is contained in:
parent
aff55fdc9e
commit
ac8d3befb7
@ -1,4 +1,6 @@
|
|||||||
list = [1 ...]
|
list = [1 ...]
|
||||||
b = list
|
b = list
|
||||||
&list.pop()
|
&list.pop()
|
||||||
|
// &list.push(5)
|
||||||
|
println(b.to_string())
|
||||||
list
|
list
|
@ -1388,9 +1388,9 @@ impl BuiltinFunction {
|
|||||||
_ => unreachable!("max: not a number"),
|
_ => unreachable!("max: not a number"),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
Self::Push => args[0].run(info).operate_on_data_mut(|list| {
|
Self::Push => args[0].run(info).operate_on_data_mut(info, |list| {
|
||||||
if let VDataEnum::Reference(v) = list {
|
if let VDataEnum::Reference(v) = list {
|
||||||
v.operate_on_data_mut(|list| {
|
v.operate_on_data_mut(info, |list| {
|
||||||
if let VDataEnum::List(_, v) = list {
|
if let VDataEnum::List(_, v) = list {
|
||||||
v.push(args[1].run(info));
|
v.push(args[1].run(info));
|
||||||
}
|
}
|
||||||
@ -1400,11 +1400,11 @@ impl BuiltinFunction {
|
|||||||
unreachable!("push: not a reference")
|
unreachable!("push: not a reference")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Self::Insert => args[0].run(info).operate_on_data_mut(|v| {
|
Self::Insert => args[0].run(info).operate_on_data_mut(info, |v| {
|
||||||
args[1].run(info).operate_on_data_immut(|i| {
|
args[1].run(info).operate_on_data_immut(|i| {
|
||||||
// TODO: find out why the fuck this helps
|
// TODO: find out why the fuck this helps
|
||||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i) {
|
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i) {
|
||||||
v.operate_on_data_mut(|v| {
|
v.operate_on_data_mut(info, |v| {
|
||||||
if let VDataEnum::List(_, v) = v {
|
if let VDataEnum::List(_, v) = v {
|
||||||
v.insert(*i as _, args[2].run(info));
|
v.insert(*i as _, args[2].run(info));
|
||||||
}
|
}
|
||||||
@ -1415,9 +1415,9 @@ impl BuiltinFunction {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
Self::Pop => args[0].run(info).operate_on_data_mut(|v| {
|
Self::Pop => args[0].run(info).operate_on_data_mut(info, |v| {
|
||||||
if let VDataEnum::Reference(v) = v {
|
if let VDataEnum::Reference(v) = v {
|
||||||
v.operate_on_data_mut(|v| {
|
v.operate_on_data_mut(info, |v| {
|
||||||
if let VDataEnum::List(_, v) = v {
|
if let VDataEnum::List(_, v) = v {
|
||||||
if let Some(v) = v.pop() {
|
if let Some(v) = v.pop() {
|
||||||
VDataEnum::Tuple(vec![v])
|
VDataEnum::Tuple(vec![v])
|
||||||
@ -1433,12 +1433,12 @@ impl BuiltinFunction {
|
|||||||
unreachable!("pop: not a reference")
|
unreachable!("pop: not a reference")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Self::Remove => args[0].run(info).operate_on_data_mut(|v| {
|
Self::Remove => args[0].run(info).operate_on_data_mut(info, |v| {
|
||||||
args[1].run(info).operate_on_data_immut(|i|
|
args[1].run(info).operate_on_data_immut(|i|
|
||||||
// this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough.
|
// this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough.
|
||||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i
|
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i
|
||||||
) {
|
) {
|
||||||
v.operate_on_data_mut(|v| {
|
v.operate_on_data_mut(info, |v| {
|
||||||
if let VDataEnum::List(_, v) = v {
|
if let VDataEnum::List(_, v) = v {
|
||||||
if *i >= 0 && v.len() > *i as _ {
|
if *i >= 0 && v.len() > *i as _ {
|
||||||
let v = v.remove(*i as _);
|
let v = v.remove(*i as _);
|
||||||
@ -1482,12 +1482,12 @@ impl BuiltinFunction {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
Self::GetRef => args[0].run(info).operate_on_data_mut(|container| {
|
Self::GetRef => args[0].run(info).operate_on_data_mut(info, |container| {
|
||||||
args[1].run(info).operate_on_data_immut(|i| {
|
args[1].run(info).operate_on_data_immut(|i| {
|
||||||
if let (VDataEnum::Reference(container), VDataEnum::Int(i)) = (container, i) {
|
if let (VDataEnum::Reference(container), VDataEnum::Int(i)) = (container, i) {
|
||||||
if *i >= 0 {
|
if *i >= 0 {
|
||||||
// we can get mutably because this is the content of a reference
|
// we can get mutably because this is the content of a reference
|
||||||
match container.operate_on_data_mut(|container| match container {
|
match container.operate_on_data_mut(info, |container| match container {
|
||||||
VDataEnum::List(_, v) | VDataEnum::Tuple(v) => {
|
VDataEnum::List(_, v) | VDataEnum::Tuple(v) => {
|
||||||
if let Some(v) = v.get_mut(*i as usize) {
|
if let Some(v) = v.get_mut(*i as usize) {
|
||||||
Some(VDataEnum::Reference(v.clone_mut()).to())
|
Some(VDataEnum::Reference(v.clone_mut()).to())
|
||||||
|
@ -112,7 +112,14 @@ impl RStatement {
|
|||||||
'init: {
|
'init: {
|
||||||
if *is_init && *derefs == 0 {
|
if *is_init && *derefs == 0 {
|
||||||
if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() {
|
if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() {
|
||||||
*var.lock().unwrap() = out;
|
let mut varl = var.lock().unwrap();
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let varname = varl.1.clone();
|
||||||
|
*varl = out;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
varl.1 = varname;
|
||||||
|
}
|
||||||
break 'init;
|
break 'init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +130,7 @@ impl RStatement {
|
|||||||
None => unreachable!("can't dereference..."),
|
None => unreachable!("can't dereference..."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
val.assign(out);
|
val.assign(info, out);
|
||||||
}
|
}
|
||||||
VDataEnum::Tuple(vec![]).to()
|
VDataEnum::Tuple(vec![]).to()
|
||||||
} else {
|
} else {
|
||||||
@ -174,7 +181,7 @@ impl RStatementEnum {
|
|||||||
}
|
}
|
||||||
Self::FunctionCall(func, args) => {
|
Self::FunctionCall(func, args) => {
|
||||||
for (i, input) in func.inputs.iter().enumerate() {
|
for (i, input) in func.inputs.iter().enumerate() {
|
||||||
input.lock().unwrap().assign(args[i].run(info));
|
input.lock().unwrap().assign(info, args[i].run(info));
|
||||||
}
|
}
|
||||||
func.run(info)
|
func.run(info)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::Display,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::libs;
|
use crate::libs;
|
||||||
|
|
||||||
use super::{builtins, val_type::VType};
|
use super::{
|
||||||
|
builtins,
|
||||||
|
val_data::VDataEnum,
|
||||||
|
val_type::{VSingleType, VType},
|
||||||
|
};
|
||||||
|
|
||||||
pub type GSInfo = Arc<GlobalScriptInfo>;
|
pub type GSInfo = Arc<GlobalScriptInfo>;
|
||||||
|
|
||||||
@ -15,6 +23,9 @@ pub struct GlobalScriptInfo {
|
|||||||
|
|
||||||
pub custom_type_names: HashMap<String, usize>,
|
pub custom_type_names: HashMap<String, usize>,
|
||||||
pub custom_types: Vec<VType>,
|
pub custom_types: Vec<VType>,
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub log: Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalScriptInfo {
|
impl GlobalScriptInfo {
|
||||||
@ -31,6 +42,8 @@ impl Default for GlobalScriptInfo {
|
|||||||
enum_variants: Self::default_enum_variants(),
|
enum_variants: Self::default_enum_variants(),
|
||||||
custom_type_names: HashMap::new(),
|
custom_type_names: HashMap::new(),
|
||||||
custom_types: vec![],
|
custom_types: vec![],
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
log: Logger::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,3 +56,85 @@ impl GlobalScriptInfo {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Logger {
|
||||||
|
logs: Arc<Mutex<Vec<LogMsg>>>,
|
||||||
|
|
||||||
|
pub vdata_clone: LogKind,
|
||||||
|
pub vtype_fits_in: LogKind,
|
||||||
|
pub vsingletype_fits_in: LogKind,
|
||||||
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl Logger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
logs: Arc::new(Mutex::new(vec![])),
|
||||||
|
vdata_clone: Default::default(),
|
||||||
|
vtype_fits_in: Default::default(),
|
||||||
|
vsingletype_fits_in: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LogMsg {
|
||||||
|
VDataClone(Option<String>, VDataEnum, usize, usize),
|
||||||
|
VTypeFitsIn(VType, VType, Vec<VSingleType>),
|
||||||
|
VSingleTypeFitsIn(VSingleType, VSingleType, bool),
|
||||||
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl Logger {
|
||||||
|
pub fn log(&self, msg: LogMsg) {
|
||||||
|
let kind = match msg {
|
||||||
|
LogMsg::VDataClone(..) => &self.vdata_clone,
|
||||||
|
LogMsg::VTypeFitsIn(..) => &self.vtype_fits_in,
|
||||||
|
LogMsg::VSingleTypeFitsIn(..) => &self.vsingletype_fits_in,
|
||||||
|
};
|
||||||
|
if kind.stderr {
|
||||||
|
eprintln!("{msg}");
|
||||||
|
}
|
||||||
|
if kind.log {
|
||||||
|
if let Ok(mut logs) = self.logs.lock() {
|
||||||
|
logs.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl Display for LogMsg {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::VDataClone(varname, data, src_addr, new_addr) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"VDataClone :: {data} ({}{src_addr} -> {new_addr})",
|
||||||
|
if let Some(v) = varname {
|
||||||
|
format!("{v} | ")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::VTypeFitsIn(a, b, no) => write!(f, "VTypeFitsIn :: {a} in {b} ? -> {no:?}"),
|
||||||
|
Self::VSingleTypeFitsIn(a, b, fits) => {
|
||||||
|
write!(f, "VSingleTypeFitsIn :: {a} in {b} ? -> {fits}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct LogKind {
|
||||||
|
pub stderr: bool,
|
||||||
|
pub log: bool,
|
||||||
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl LogKind {
|
||||||
|
pub fn log(&self) -> bool {
|
||||||
|
self.stderr || self.log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -223,6 +223,9 @@ fn get_all_functions(
|
|||||||
vartype.to()
|
vartype.to()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// block is parsed multiple times (this is why we get duplicates in stderr):
|
||||||
|
// - n times for the function args to generate the input-output map
|
||||||
|
// - 1 more time here, where the function args aren't single types
|
||||||
out.push((
|
out.push((
|
||||||
inputs.clone(),
|
inputs.clone(),
|
||||||
block(&s.block, ginfo, linfo.clone())?.out(ginfo),
|
block(&s.block, ginfo, linfo.clone())?.out(ginfo),
|
||||||
@ -367,7 +370,11 @@ fn statement_adv(
|
|||||||
if !linfo.vars.contains_key(v) {
|
if !linfo.vars.contains_key(v) {
|
||||||
if let Some((t, is_init)) = to_be_assigned_to {
|
if let Some((t, is_init)) = to_be_assigned_to {
|
||||||
*is_init = true;
|
*is_init = true;
|
||||||
linfo.vars.insert(v.to_owned(), (Arc::new(Mutex::new(VData::new_placeholder())), t));
|
#[cfg(not(debug_assertions))]
|
||||||
|
let var = VData::new_placeholder();
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let var = VData::new_placeholder_with_name(v.to_owned());
|
||||||
|
linfo.vars.insert(v.to_owned(), (Arc::new(Mutex::new(var)), t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(var) = linfo.vars.get(v) {
|
if let Some(var) = linfo.vars.get(v) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Debug, Display, Formatter},
|
fmt::{self, Debug, Display, Formatter},
|
||||||
|
ops::Deref,
|
||||||
sync::{Arc, Mutex, MutexGuard},
|
sync::{Arc, Mutex, MutexGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9,6 +10,9 @@ use super::{
|
|||||||
val_type::{VSingleType, VType},
|
val_type::{VSingleType, VType},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use super::global_info::LogMsg;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VDataEnum {
|
pub enum VDataEnum {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
@ -23,8 +27,11 @@ pub enum VDataEnum {
|
|||||||
EnumVariant(usize, Box<VData>),
|
EnumVariant(usize, Box<VData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub struct VData(Arc<Mutex<VDataInner>>);
|
pub struct VData(Arc<Mutex<VDataInner>>);
|
||||||
enum VDataInner {
|
#[cfg(debug_assertions)]
|
||||||
|
pub struct VData(pub Arc<Mutex<VDataInner>>, pub Option<String>);
|
||||||
|
pub enum VDataInner {
|
||||||
Data(usize, Box<VDataEnum>),
|
Data(usize, Box<VDataEnum>),
|
||||||
Mut(Arc<Mutex<VData>>),
|
Mut(Arc<Mutex<VData>>),
|
||||||
ClonedFrom(VData),
|
ClonedFrom(VData),
|
||||||
@ -35,7 +42,10 @@ enum VDataInner {
|
|||||||
/// - any Mut will eventually point to a ClonedFrom or a Data variant. It can also point to another Mut.
|
/// - any Mut will eventually point to a ClonedFrom or a Data variant. It can also point to another Mut.
|
||||||
impl VDataInner {
|
impl VDataInner {
|
||||||
fn to(self) -> VData {
|
fn to(self) -> VData {
|
||||||
VData(Arc::new(Mutex::new(self)))
|
#[cfg(not(debug_assertions))]
|
||||||
|
return VData(Arc::new(Mutex::new(self)));
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
return VData(Arc::new(Mutex::new(self)), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl VDataEnum {
|
impl VDataEnum {
|
||||||
@ -48,9 +58,17 @@ impl VData {
|
|||||||
pub fn new_placeholder() -> Self {
|
pub fn new_placeholder() -> Self {
|
||||||
VDataEnum::Bool(false).to()
|
VDataEnum::Bool(false).to()
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn new_placeholder_with_name(name: String) -> Self {
|
||||||
|
let mut o = VDataEnum::Bool(false).to();
|
||||||
|
o.1 = Some(name);
|
||||||
|
o
|
||||||
|
}
|
||||||
/// clones self, retrurning a new instance of self that will always yield the value self had when this function was called.
|
/// clones self, retrurning a new instance of self that will always yield the value self had when this function was called.
|
||||||
/// note to dev: since the actual data is stored in VDataEnum, which either clones data or calls clone() (= clone_data()) on further VData, this automatically borrows all child data as immutable too. rust's Drop::drop() implementation (probably) handles everything for us too, so this can be implemented without thinking about recursion.
|
/// note to dev: since the actual data is stored in VDataEnum, which either clones data or calls clone() (= clone_data()) on further VData, this automatically borrows all child data as immutable too. rust's Drop::drop() implementation (probably) handles everything for us too, so this can be implemented without thinking about recursion.
|
||||||
pub fn clone_data(&self) -> Self {
|
pub fn clone_data(&self) -> Self {
|
||||||
|
// TODO! implement CopyOnWrite. For now, just always copy. This also prevents mut references not existing since in ::Dat(cloned, _), cloned will always stay 0.
|
||||||
|
return self.operate_on_data_immut(|v| v.clone()).to();
|
||||||
match &mut *self.0.lock().unwrap() {
|
match &mut *self.0.lock().unwrap() {
|
||||||
VDataInner::Data(cloned, _data) => {
|
VDataInner::Data(cloned, _data) => {
|
||||||
*cloned += 1;
|
*cloned += 1;
|
||||||
@ -65,7 +83,10 @@ impl VData {
|
|||||||
VDataInner::Mut(Arc::new(Mutex::new(self.clone_arc()))).to()
|
VDataInner::Mut(Arc::new(Mutex::new(self.clone_arc()))).to()
|
||||||
}
|
}
|
||||||
fn clone_arc(&self) -> Self {
|
fn clone_arc(&self) -> Self {
|
||||||
Self(Arc::clone(&self.0))
|
#[cfg(not(debug_assertions))]
|
||||||
|
return Self(Arc::clone(&self.0));
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
return Self(Arc::clone(&self.0), self.1.clone());
|
||||||
}
|
}
|
||||||
pub fn operate_on_data_immut<F, O>(&self, mut func: F) -> O
|
pub fn operate_on_data_immut<F, O>(&self, mut func: F) -> O
|
||||||
where
|
where
|
||||||
@ -80,27 +101,39 @@ impl VData {
|
|||||||
/// runs func on the underlying data.
|
/// runs func on the underlying data.
|
||||||
/// attempts to get a mutable reference to the data. if this fails, it will (partially) clone the data, then point the VData to the new data,
|
/// attempts to get a mutable reference to the data. if this fails, it will (partially) clone the data, then point the VData to the new data,
|
||||||
/// so that other VDatas pointing to the same original data aren't changed.
|
/// so that other VDatas pointing to the same original data aren't changed.
|
||||||
pub fn operate_on_data_mut<F, O>(&mut self, mut func: F) -> O
|
pub fn operate_on_data_mut<F, O>(&mut self, info: &GlobalScriptInfo, mut func: F) -> O
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut VDataEnum) -> O,
|
F: FnOnce(&mut VDataEnum) -> O,
|
||||||
{
|
{
|
||||||
let (new_val, o) = {
|
let (new_val, o) = {
|
||||||
match &mut *self.0.lock().unwrap() {
|
let mut lock = self.0.lock().unwrap();
|
||||||
|
match &mut *lock {
|
||||||
VDataInner::Data(count, data) => {
|
VDataInner::Data(count, data) => {
|
||||||
if *count == 0 {
|
if *count == 0 {
|
||||||
(None, func(data.as_mut()))
|
(None, func(data.as_mut()))
|
||||||
} else {
|
} else {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
eprintln!("Cloning: data should be modified, but was borrowed immutably.");
|
|
||||||
let mut new_data = data.clone();
|
let mut new_data = data.clone();
|
||||||
let o = func(new_data.as_mut());
|
let o = func(new_data.as_mut());
|
||||||
// *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was.
|
// *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was.
|
||||||
// for proof: data is untouched, only the new_data is ever modified.
|
// for proof: data is untouched, only the new_data is ever modified.
|
||||||
(Some(VDataInner::Data(0, new_data).to()), o)
|
let new_vdata = VDataInner::Data(0, new_data).to();
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if info.log.vdata_clone.log() {
|
||||||
|
drop(lock);
|
||||||
|
info.log.log(LogMsg::VDataClone(
|
||||||
|
self.1.clone(),
|
||||||
|
self.inner_cloned(),
|
||||||
|
Arc::as_ptr(&self.0) as usize,
|
||||||
|
Arc::as_ptr(&new_vdata.0) as usize,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(Some(new_vdata), o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VDataInner::Mut(inner) => (None, inner.lock().unwrap().operate_on_data_mut(func)),
|
VDataInner::Mut(inner) => {
|
||||||
VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(func)),
|
(None, inner.lock().unwrap().operate_on_data_mut(info, func))
|
||||||
|
}
|
||||||
|
VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(info, func)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(nv) = new_val {
|
if let Some(nv) = new_val {
|
||||||
@ -111,12 +144,13 @@ impl VData {
|
|||||||
|
|
||||||
/// Since operate_on_data_mut can clone, it may be inefficient for just assigning (where we don't care about the previous value, so it doesn't need to be cloned).
|
/// Since operate_on_data_mut can clone, it may be inefficient for just assigning (where we don't care about the previous value, so it doesn't need to be cloned).
|
||||||
/// This is what this function is for. (TODO: actually make it more efficient instead of using operate_on_data_mut)
|
/// This is what this function is for. (TODO: actually make it more efficient instead of using operate_on_data_mut)
|
||||||
pub fn assign_data(&mut self, new_data: VDataEnum) {
|
pub fn assign_data(&mut self, info: &GlobalScriptInfo, new_data: VDataEnum) {
|
||||||
self.operate_on_data_mut(|d| *d = new_data)
|
let o = self.operate_on_data_mut(info, |d| *d = new_data);
|
||||||
|
o
|
||||||
}
|
}
|
||||||
/// Assigns the new_data to self. Affects all muts pointing to the same data, but no ClonedFroms.
|
/// Assigns the new_data to self. Affects all muts pointing to the same data, but no ClonedFroms.
|
||||||
pub fn assign(&mut self, new: VData) {
|
pub fn assign(&mut self, info: &GlobalScriptInfo, new: VData) {
|
||||||
self.assign_data(new.inner_cloned())
|
self.assign_data(info, new.inner_cloned())
|
||||||
// !PROBLEM! If ClonedFrom always has to point to a Data, this may break things!
|
// !PROBLEM! If ClonedFrom always has to point to a Data, this may break things!
|
||||||
// match &mut *self.0.lock().unwrap() {
|
// match &mut *self.0.lock().unwrap() {
|
||||||
// VDataInner::Data(count, data) => {
|
// VDataInner::Data(count, data) => {
|
||||||
@ -133,9 +167,7 @@ impl Drop for VDataInner {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Self::ClonedFrom(origin) = self {
|
if let Self::ClonedFrom(origin) = self {
|
||||||
if let Self::Data(ref_count, _data) = &mut *origin.0.lock().unwrap() {
|
if let Self::Data(ref_count, _data) = &mut *origin.0.lock().unwrap() {
|
||||||
eprint!("rc: {}", *ref_count);
|
// *ref_count = ref_count.saturating_sub(1);
|
||||||
*ref_count = ref_count.saturating_sub(1);
|
|
||||||
eprintln!(" -> {}", *ref_count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ use std::{
|
|||||||
|
|
||||||
use super::global_info::{self, GSInfo, GlobalScriptInfo};
|
use super::global_info::{self, GSInfo, GlobalScriptInfo};
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use super::global_info::LogMsg;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct VType {
|
pub struct VType {
|
||||||
pub types: Vec<VSingleType>,
|
pub types: Vec<VSingleType>,
|
||||||
@ -151,8 +154,6 @@ impl VType {
|
|||||||
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.
|
/// 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, info: &GlobalScriptInfo) -> Vec<VSingleType> {
|
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> Vec<VSingleType> {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
eprintln!("{} in {}? [VType]", self, rhs);
|
|
||||||
let mut no = vec![];
|
let mut no = vec![];
|
||||||
for t in &self.types {
|
for t in &self.types {
|
||||||
// if t doesnt fit in any of rhs's types
|
// if t doesnt fit in any of rhs's types
|
||||||
@ -160,6 +161,11 @@ impl VType {
|
|||||||
no.push(t.clone())
|
no.push(t.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if info.log.vtype_fits_in.log() {
|
||||||
|
info.log
|
||||||
|
.log(LogMsg::VTypeFitsIn(self.clone(), rhs.clone(), no.clone()))
|
||||||
|
}
|
||||||
no
|
no
|
||||||
}
|
}
|
||||||
pub fn inner_types(&self) -> VType {
|
pub fn inner_types(&self) -> VType {
|
||||||
@ -294,8 +300,6 @@ impl VSingleType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool {
|
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
eprintln!("{self} in {rhs}?");
|
|
||||||
let o = match (self, rhs) {
|
let o = match (self, rhs) {
|
||||||
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b, info),
|
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b, info),
|
||||||
(Self::Reference(_), _) | (_, Self::Reference(_)) => false,
|
(Self::Reference(_), _) | (_, Self::Reference(_)) => false,
|
||||||
@ -356,7 +360,10 @@ impl VSingleType {
|
|||||||
(Self::Thread(..), _) => false,
|
(Self::Thread(..), _) => false,
|
||||||
};
|
};
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
eprintln!(" -> {}", o);
|
if info.log.vsingletype_fits_in.log() {
|
||||||
|
info.log
|
||||||
|
.log(LogMsg::VSingleTypeFitsIn(self.clone(), rhs.clone(), o));
|
||||||
|
}
|
||||||
o
|
o
|
||||||
}
|
}
|
||||||
pub fn fits_in_type(&self, rhs: &VType, info: &GlobalScriptInfo) -> bool {
|
pub fn fits_in_type(&self, rhs: &VType, info: &GlobalScriptInfo) -> bool {
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
use std::{fs, time::Instant};
|
use std::{fs, time::Instant};
|
||||||
|
|
||||||
|
use lang::global_info::GlobalScriptInfo;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use lang::global_info::LogKind;
|
||||||
use notify::Watcher as FsWatcher;
|
use notify::Watcher as FsWatcher;
|
||||||
|
|
||||||
mod interactive_mode;
|
mod interactive_mode;
|
||||||
@ -22,14 +25,8 @@ fn main() {
|
|||||||
|
|
||||||
fn normal_main() {
|
fn normal_main() {
|
||||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||||
#[cfg(debug_assertions)]
|
let mut info = GlobalScriptInfo::default();
|
||||||
let args = if args.len() == 0 {
|
let mut args_to_skip = 2;
|
||||||
let mut args = args;
|
|
||||||
args.push("../script.mers".to_owned());
|
|
||||||
args
|
|
||||||
} else {
|
|
||||||
args
|
|
||||||
};
|
|
||||||
let mut file = match args.len() {
|
let mut file = match args.len() {
|
||||||
0 => {
|
0 => {
|
||||||
println!("Please provide some arguments, such as the path to a file or \"-e <code>\".");
|
println!("Please provide some arguments, such as the path to a file or \"-e <code>\".");
|
||||||
@ -39,7 +36,8 @@ fn normal_main() {
|
|||||||
if args[0].trim_start().starts_with("-") {
|
if args[0].trim_start().starts_with("-") {
|
||||||
let mut execute = false;
|
let mut execute = false;
|
||||||
let mut print_version = false;
|
let mut print_version = false;
|
||||||
let mut verbose = 0;
|
let mut verbose = false;
|
||||||
|
let mut verbose_args = String::new();
|
||||||
let mut interactive = 0;
|
let mut interactive = 0;
|
||||||
let mut interactive_use_new_terminal = false;
|
let mut interactive_use_new_terminal = false;
|
||||||
let mut teachme = false;
|
let mut teachme = false;
|
||||||
@ -53,7 +51,7 @@ fn normal_main() {
|
|||||||
}
|
}
|
||||||
match ch {
|
match ch {
|
||||||
'e' => execute = true,
|
'e' => execute = true,
|
||||||
'v' => verbose += 1,
|
'v' => verbose = true,
|
||||||
'V' => print_version = true,
|
'V' => print_version = true,
|
||||||
'i' => interactive += 1,
|
'i' => interactive += 1,
|
||||||
't' => teachme = true,
|
't' => teachme = true,
|
||||||
@ -64,12 +62,19 @@ fn normal_main() {
|
|||||||
}
|
}
|
||||||
prev_char = Some(ch);
|
prev_char = Some(ch);
|
||||||
} else {
|
} else {
|
||||||
|
advanced = false;
|
||||||
if let Some(prev_char) = prev_char {
|
if let Some(prev_char) = prev_char {
|
||||||
match prev_char {
|
match prev_char {
|
||||||
'i' => match ch {
|
'i' => match ch {
|
||||||
't' => interactive_use_new_terminal = true,
|
't' => interactive_use_new_terminal = true,
|
||||||
_ => eprintln!("Ignoring i+{ch}. (unknown adv char)"),
|
_ => eprintln!("Ignoring i+{ch}. (unknown adv char)"),
|
||||||
},
|
},
|
||||||
|
'v' => {
|
||||||
|
if ch != '+' {
|
||||||
|
advanced = true;
|
||||||
|
verbose_args.push(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -77,7 +82,6 @@ fn normal_main() {
|
|||||||
"Ignoring advanced args because there was no previous argument."
|
"Ignoring advanced args because there was no previous argument."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
advanced = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if print_version {
|
if print_version {
|
||||||
@ -92,8 +96,55 @@ fn normal_main() {
|
|||||||
tutor::start(false);
|
tutor::start(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if verbose != 0 {
|
if verbose {
|
||||||
eprintln!("info: set verbosity level to {verbose}. this doesn't do anything yet. [TODO!]");
|
#[cfg(not(debug_assertions))]
|
||||||
|
eprintln!("WARN: Verbose (-v) only works in debug builds!");
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if verbose_args.is_empty() {
|
||||||
|
fn f() -> LogKind {
|
||||||
|
LogKind {
|
||||||
|
stderr: true,
|
||||||
|
log: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.log.vdata_clone = f();
|
||||||
|
info.log.vtype_fits_in = f();
|
||||||
|
info.log.vsingletype_fits_in = f();
|
||||||
|
} else {
|
||||||
|
fn kind(val: Option<&str>) -> LogKind {
|
||||||
|
match val {
|
||||||
|
Some("stderr") => LogKind {
|
||||||
|
stderr: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some("log") => LogKind {
|
||||||
|
log: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some("log+stderr" | "stderr+log") => LogKind {
|
||||||
|
stderr: true,
|
||||||
|
log: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
_ => LogKind {
|
||||||
|
stderr: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for verbose_arg in verbose_args.split(',') {
|
||||||
|
let (arg, val) = match verbose_arg.split_once('=') {
|
||||||
|
Some((left, right)) => (left, Some(right)),
|
||||||
|
None => (verbose_arg, None),
|
||||||
|
};
|
||||||
|
match arg {
|
||||||
|
"vdata_clone" => info.log.vdata_clone = kind(val),
|
||||||
|
"vtype_fits_in" => info.log.vtype_fits_in = kind(val),
|
||||||
|
"vsingletype_fits_in" => info.log.vsingletype_fits_in = kind(val),
|
||||||
|
_ => eprintln!("Warn: -v+ unknown arg '{arg}'."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if interactive > 0 {
|
if interactive > 0 {
|
||||||
match interactive {
|
match interactive {
|
||||||
@ -114,10 +165,18 @@ fn normal_main() {
|
|||||||
}),
|
}),
|
||||||
std::path::PathBuf::new(),
|
std::path::PathBuf::new(),
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
args_to_skip += 1;
|
||||||
|
if let Some(file) = args.get(1) {
|
||||||
|
parsing::file::File::new(
|
||||||
|
std::fs::read_to_string(file).unwrap(),
|
||||||
|
file.into(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
println!("please provide either a file or -e and a script to run!");
|
println!("please provide either a file or -e and a script to run!");
|
||||||
std::process::exit(101);
|
std::process::exit(101);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
parsing::file::File::new(
|
parsing::file::File::new(
|
||||||
std::fs::read_to_string(&args[0]).unwrap(),
|
std::fs::read_to_string(&args[0]).unwrap(),
|
||||||
@ -126,13 +185,11 @@ fn normal_main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match parsing::parse::parse(&mut file) {
|
match parsing::parse::parse_custom_info(&mut file, info) {
|
||||||
Ok(script) => {
|
Ok(script) => {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
eprintln!("{script:#?}");
|
|
||||||
println!(" - - - - -");
|
println!(" - - - - -");
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let out = script.run(std::env::args().skip(2).collect());
|
let out = script.run(std::env::args().skip(args_to_skip).collect());
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
println!(" - - - - -");
|
println!(" - - - - -");
|
||||||
println!("Output ({}s)\n{out}", elapsed.as_secs_f64());
|
println!("Output ({}s)\n{out}", elapsed.as_secs_f64());
|
||||||
|
@ -216,8 +216,8 @@ impl Iterator for File {
|
|||||||
}
|
}
|
||||||
_ => self.pos.current_column += 1,
|
_ => self.pos.current_column += 1,
|
||||||
}
|
}
|
||||||
#[cfg(debug_assertions)]
|
// #[cfg(debug_assertions)]
|
||||||
eprint!("{ch}");
|
// eprint!("{ch}");
|
||||||
Some(*ch)
|
Some(*ch)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -136,8 +136,10 @@ impl Error {
|
|||||||
|
|
||||||
/// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile
|
/// executes the 4 parse_steps in order: lib_paths => interpret => libs_load => compile
|
||||||
pub fn parse(file: &mut File) -> Result<RScript, Error> {
|
pub fn parse(file: &mut File) -> Result<RScript, Error> {
|
||||||
let mut ginfo = GlobalScriptInfo::default();
|
parse_custom_info(file, GlobalScriptInfo::default())
|
||||||
|
}
|
||||||
|
/// like parse, but GlobalInfo can be something other than Default::default().
|
||||||
|
pub fn parse_custom_info(file: &mut File, mut ginfo: GlobalScriptInfo) -> Result<RScript, Error> {
|
||||||
let libs = match parse_step_lib_paths(file) {
|
let libs = match parse_step_lib_paths(file) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => return Err((e.into(), ginfo.to_arc()).into()),
|
Err(e) => return Err((e.into(), ginfo.to_arc()).into()),
|
||||||
|
Loading…
Reference in New Issue
Block a user