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:
Dummi26 2023-03-13 23:05:27 +01:00
parent a4fbb8dd97
commit d0cf7ab588
4 changed files with 309 additions and 20 deletions

View File

@ -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() {

View File

@ -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()),
}
}
}

View File

@ -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")
}
}
}
}
}

View File

@ -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,
}
}
}