mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
added the concept of references: prefix any (single) type or variable with & to get a reference. This is used for List.{push, insert, pop, remove, get} to avoid copying the list unnecessarily.
This commit is contained in:
parent
a4fbb8dd97
commit
d0cf7ab588
@ -141,11 +141,6 @@ fn parse_statement_adv(
|
||||
SStatementEnum::Tuple(v).into()
|
||||
})
|
||||
}
|
||||
Some('$') => {
|
||||
file.next();
|
||||
file.skip_whitespaces();
|
||||
Some(SStatementEnum::Variable(file.take_while(|v| !v.is_whitespace()).collect()).into())
|
||||
}
|
||||
Some('"') => {
|
||||
file.next();
|
||||
let mut buf = String::new();
|
||||
@ -280,15 +275,22 @@ fn parse_statement_adv(
|
||||
break SStatementEnum::Value(VDataEnum::Bool(false).to()).into()
|
||||
}
|
||||
_ => {
|
||||
// int, float, var
|
||||
break {
|
||||
if let Ok(v) = start.parse() {
|
||||
SStatementEnum::Value(VDataEnum::Int(v).to()).into()
|
||||
} else if let Ok(v) = start.replace(",", ".").parse() {
|
||||
SStatementEnum::Value(VDataEnum::Float(v).to()).into()
|
||||
} else {
|
||||
SStatementEnum::Variable(start.to_string()).into()
|
||||
if start.starts_with('&') {
|
||||
SStatementEnum::Variable(start[1..].to_string(), true)
|
||||
.into()
|
||||
} else {
|
||||
SStatementEnum::Variable(start.to_string(), false)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -378,9 +380,7 @@ fn parse_type(file: &mut File) -> Result<VType, ParseError> {
|
||||
fn parse_type_adv(file: &mut File, in_fn_args: bool) -> Result<(VType, bool), ParseError> {
|
||||
let mut types = vec![];
|
||||
let mut closed_fn_args = false;
|
||||
let mut count = 0;
|
||||
loop {
|
||||
count += 1;
|
||||
let (st, closed_bracket) = parse_single_type_adv(file, in_fn_args)?;
|
||||
types.push(st);
|
||||
if closed_bracket {
|
||||
@ -414,6 +414,13 @@ fn parse_single_type_adv(
|
||||
let mut closed_bracket_in_fn_args = false;
|
||||
Ok((
|
||||
match file.next() {
|
||||
Some('&') => {
|
||||
let parse_output = parse_single_type_adv(file, in_fn_args)?;
|
||||
if parse_output.1 {
|
||||
closed_bracket_in_fn_args = true;
|
||||
}
|
||||
VSingleType::Reference(Box::new(parse_output.0))
|
||||
}
|
||||
// Tuple or Array
|
||||
Some('[') => {
|
||||
let mut types = vec![];
|
||||
@ -439,6 +446,7 @@ fn parse_single_type_adv(
|
||||
loop {
|
||||
match file.peek() {
|
||||
Some(']') => break,
|
||||
Some('/') => break,
|
||||
_ => (),
|
||||
}
|
||||
match file.next() {
|
||||
|
@ -59,7 +59,7 @@ pub enum SStatementEnum {
|
||||
Value(VData),
|
||||
Tuple(Vec<SStatement>),
|
||||
List(Vec<SStatement>),
|
||||
Variable(String),
|
||||
Variable(String, bool),
|
||||
FunctionCall(String, Vec<SStatement>),
|
||||
FunctionDefinition(Option<String>, SFunction),
|
||||
Block(SBlock),
|
||||
@ -266,9 +266,9 @@ pub mod to_runnable {
|
||||
RStatementEnum::Tuple(w)
|
||||
}
|
||||
}
|
||||
SStatementEnum::Variable(v) => {
|
||||
SStatementEnum::Variable(v, is_ref) => {
|
||||
if let Some(var) = linfo.vars.get(v) {
|
||||
RStatementEnum::Variable(var.0, var.1.clone())
|
||||
RStatementEnum::Variable(var.0, var.1.clone(), *is_ref)
|
||||
} else {
|
||||
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
||||
}
|
||||
@ -405,7 +405,7 @@ pub mod to_runnable {
|
||||
}
|
||||
}
|
||||
RStatementEnum::Switch(
|
||||
RStatementEnum::Variable(switch_on_v.0, switch_on_out).to(),
|
||||
RStatementEnum::Variable(switch_on_v.0, switch_on_out, false).to(),
|
||||
ncases,
|
||||
)
|
||||
} else {
|
||||
@ -554,7 +554,7 @@ pub enum RStatementEnum {
|
||||
Value(VData),
|
||||
Tuple(Vec<RStatement>),
|
||||
List(Vec<RStatement>),
|
||||
Variable(usize, VType), // Arc<Mutex<..>> here, because imagine variable in for loop that is used in a different thread -> we need multiple "same" variables
|
||||
Variable(usize, VType, bool), // Arc<Mutex<..>> here, because imagine variable in for loop that is used in a different thread -> we need multiple "same" variables
|
||||
FunctionCall(Arc<RFunction>, Vec<RStatement>),
|
||||
BuiltinFunction(BuiltinFunction, Vec<RStatement>),
|
||||
Block(RBlock),
|
||||
@ -585,7 +585,13 @@ impl RStatementEnum {
|
||||
}
|
||||
VDataEnum::List(out, w).to()
|
||||
}
|
||||
Self::Variable(v, _) => vars[*v].lock().unwrap().clone(),
|
||||
Self::Variable(v, _, is_ref) => {
|
||||
if *is_ref {
|
||||
VDataEnum::Reference(vars[*v].clone()).to()
|
||||
} else {
|
||||
vars[*v].lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
Self::FunctionCall(func, args) => {
|
||||
for (i, input) in func.inputs.iter().enumerate() {
|
||||
*vars[*input].lock().unwrap() = args[i].run(vars);
|
||||
@ -627,6 +633,7 @@ impl RStatementEnum {
|
||||
vars[*v] = Arc::new(Mutex::new(c));
|
||||
b.run(&vars);
|
||||
};
|
||||
|
||||
match c.data {
|
||||
VDataEnum::Int(v) => {
|
||||
for i in 0..v {
|
||||
@ -666,10 +673,28 @@ impl RStatementEnum {
|
||||
pub fn out(&self) -> VType {
|
||||
match self {
|
||||
Self::Value(v) => v.out(),
|
||||
Self::Tuple(v) | Self::List(v) => {
|
||||
VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into()
|
||||
Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into(),
|
||||
Self::List(v) => VSingleType::List({
|
||||
let mut types = VType { types: vec![] };
|
||||
for t in v {
|
||||
types = types | t.out();
|
||||
}
|
||||
types
|
||||
})
|
||||
.into(),
|
||||
Self::Variable(_, t, is_ref) => {
|
||||
if *is_ref {
|
||||
VType {
|
||||
types: t
|
||||
.types
|
||||
.iter()
|
||||
.map(|t| VSingleType::Reference(Box::new(t.clone())))
|
||||
.collect(),
|
||||
}
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}
|
||||
Self::Variable(_, t) => t.clone(),
|
||||
Self::FunctionCall(f, _) => {
|
||||
eprintln!("Warn: generalizing a functions return type regardless of the inputs. Type-checker might assume this value can have more types than it really can.");
|
||||
f.out_all()
|
||||
@ -793,6 +818,7 @@ impl Display for VSingleType {
|
||||
Self::List(t) => write!(f, "[{t}]"),
|
||||
Self::Function(args, out) => write!(f, "({args:?}) -> {out}"),
|
||||
Self::Thread(_) => write!(f, "THREAD"),
|
||||
Self::Reference(r) => write!(f, "&{r}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -822,7 +848,9 @@ impl Display for SStatementEnum {
|
||||
v.iter().map(|v| format!("{} ", v)).collect::<String>()
|
||||
)
|
||||
}
|
||||
SStatementEnum::Variable(v) => write!(f, "{v}"),
|
||||
SStatementEnum::Variable(v, is_ref) => {
|
||||
write!(f, "{}{v}", if *is_ref { "&" } else { "" })
|
||||
}
|
||||
SStatementEnum::FunctionCall(func, args) => {
|
||||
write!(f, "{func}(")?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
@ -902,6 +930,7 @@ impl Display for VDataEnum {
|
||||
}
|
||||
Self::Function(v) => write!(f, "{v}"),
|
||||
Self::Thread(..) => write!(f, "THREAD"),
|
||||
Self::Reference(r) => write!(f, "{}", r.lock().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,20 @@ pub enum BuiltinFunction {
|
||||
// OS
|
||||
RunCommand,
|
||||
RunCommandGetBytes,
|
||||
// Math
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Pow,
|
||||
// List
|
||||
Push,
|
||||
Insert,
|
||||
Pop,
|
||||
Remove,
|
||||
Get,
|
||||
Len,
|
||||
}
|
||||
|
||||
impl BuiltinFunction {
|
||||
@ -62,6 +76,18 @@ impl BuiltinFunction {
|
||||
"string_to_bytes" => Self::StringToBytes,
|
||||
"run_command" => Self::RunCommand,
|
||||
"run_command_get_bytes" => Self::RunCommandGetBytes,
|
||||
"add" => Self::Add,
|
||||
"sub" => Self::Sub,
|
||||
"mul" => Self::Mul,
|
||||
"div" => Self::Div,
|
||||
"mod" => Self::Mod,
|
||||
"pow" => Self::Pow,
|
||||
"push" => Self::Push,
|
||||
"insert" => Self::Insert,
|
||||
"pop" => Self::Pop,
|
||||
"remove" => Self::Remove,
|
||||
"get" => Self::Get,
|
||||
"len" => Self::Len,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@ -74,7 +100,7 @@ impl BuiltinFunction {
|
||||
// String
|
||||
Self::ToString | Self::Format => VSingleType::String.into(),
|
||||
// !
|
||||
Self::Run | Self::Thread | Self::Await => {
|
||||
Self::Run | Self::Thread | Self::Await | Self::Pop | Self::Remove | Self::Get => {
|
||||
VType { types: vec![] } // TODO!
|
||||
// unreachable!("this has to be implemented somewhere else!")
|
||||
}
|
||||
@ -136,6 +162,11 @@ impl BuiltinFunction {
|
||||
]),
|
||||
],
|
||||
},
|
||||
Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Mod | Self::Pow => VType {
|
||||
types: vec![VSingleType::Int, VSingleType::Float],
|
||||
},
|
||||
Self::Push | Self::Insert => VSingleType::Tuple(vec![]).into(),
|
||||
Self::Len => VSingleType::Int.into(),
|
||||
}
|
||||
}
|
||||
pub fn run(&self, args: &Vec<RStatement>, vars: &Vec<Arc<Mutex<VData>>>) -> VData {
|
||||
@ -443,6 +474,220 @@ impl BuiltinFunction {
|
||||
unreachable!("run_command not 1 arg")
|
||||
}
|
||||
}
|
||||
Self::Add => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a + b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 + b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a + b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a + b).to(),
|
||||
_ => unreachable!("add: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("add: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Sub => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a - b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 - b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a - b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a - b).to(),
|
||||
_ => unreachable!("sub: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("sub: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Mul => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a * b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 * b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a * b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a * b).to(),
|
||||
_ => unreachable!("mul: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("mul: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Div => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a / b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 / b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a / b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a / b).to(),
|
||||
_ => unreachable!("div: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("div: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Mod => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a % b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 % b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a % b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a % b).to(),
|
||||
_ => unreachable!("mod: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("mod: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Pow => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if b == 0 {
|
||||
1
|
||||
} else if b > 0 {
|
||||
a.pow(b as _)
|
||||
} else {
|
||||
0
|
||||
})
|
||||
.to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float((a as f64).powf(b)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a.powi(b as _)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a.powf(b)).to()
|
||||
}
|
||||
_ => unreachable!("pow: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("pow: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Push => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars).data {
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.push(args[1].run(vars));
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
unreachable!("push: not a reference")
|
||||
}
|
||||
} else {
|
||||
unreachable!("push: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Insert => {
|
||||
if args.len() == 3 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.insert(i as _, args[2].run(vars));
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
unreachable!("insert: not a reference and index")
|
||||
}
|
||||
} else {
|
||||
unreachable!("insert: not 3 args")
|
||||
}
|
||||
}
|
||||
Self::Pop => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars).data {
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.pop().unwrap_or_else(|| VDataEnum::Tuple(vec![]).to())
|
||||
} else {
|
||||
unreachable!("pop: not a list")
|
||||
}
|
||||
} else {
|
||||
unreachable!("pop: not a reference")
|
||||
}
|
||||
} else {
|
||||
unreachable!("pop: not 1 arg")
|
||||
}
|
||||
}
|
||||
Self::Remove => {
|
||||
if args.len() == 2 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
if v.len() > i as _ && i >= 0 {
|
||||
v.remove(i as _)
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
} else {
|
||||
unreachable!("remove: not a list")
|
||||
}
|
||||
} else {
|
||||
unreachable!("remove: not a reference and index")
|
||||
}
|
||||
} else {
|
||||
unreachable!("remove: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Get => {
|
||||
if args.len() == 2 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
if i >= 0 {
|
||||
match v.get(i as usize) {
|
||||
Some(v) => v.clone(),
|
||||
None => VDataEnum::Tuple(vec![]).to(),
|
||||
}
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
} else {
|
||||
unreachable!("get: not a list")
|
||||
}
|
||||
} else {
|
||||
unreachable!("get: not a reference and index")
|
||||
}
|
||||
} else {
|
||||
unreachable!("get: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Len => {
|
||||
if args.len() == 1 {
|
||||
VDataEnum::Int(match args[0].run(vars).data {
|
||||
VDataEnum::String(v) => v.len(),
|
||||
VDataEnum::Tuple(v) => v.len(),
|
||||
VDataEnum::List(_, v) => v.len(),
|
||||
_ => unreachable!("len: invalid type"),
|
||||
} as _)
|
||||
.to()
|
||||
} else {
|
||||
unreachable!("len: not 1 arg")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ impl VData {
|
||||
f.out_all()
|
||||
}),
|
||||
VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()),
|
||||
VDataEnum::Reference(r) => r.lock().unwrap().out_single(),
|
||||
}
|
||||
}
|
||||
pub fn get(&self, i: usize) -> Option<Self> {
|
||||
@ -49,6 +50,7 @@ pub enum VDataEnum {
|
||||
List(VType, Vec<VData>),
|
||||
Function(RFunction),
|
||||
Thread(VDataThread, VType),
|
||||
Reference(Arc<Mutex<VData>>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -136,6 +138,7 @@ impl VDataEnum {
|
||||
None => None,
|
||||
},
|
||||
Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(),
|
||||
Self::Reference(r) => r.lock().unwrap().get(i),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,6 +150,7 @@ impl VSingleType {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,6 +213,7 @@ pub enum VSingleType {
|
||||
List(VType),
|
||||
Function(Vec<VType>, VType),
|
||||
Thread(VType),
|
||||
Reference(Box<Self>),
|
||||
}
|
||||
impl VSingleType {
|
||||
pub fn inner_types(&self) -> Vec<VSingleType> {
|
||||
@ -256,6 +261,8 @@ impl VSingleType {
|
||||
(Self::Function(..), _) => false,
|
||||
(Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(),
|
||||
(Self::Thread(..), _) => false,
|
||||
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b),
|
||||
(Self::Reference(_), _) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user