added iterators: any function that takes no arguments can be used in a for loop. Each iteration, it will be called once. If its value matches, the for loop will execute its block with that value. If the value doesn't match, the for loop will stop. This also required adding function types: fn((input11 input12 output1) (input21 input22 output2)). The type maps inputs to outputs, because the add function isn't add(int/float int/float) -> int/float, but rather add((int int int) (int float float) (float int float) (float float float)) (notice that add(int int) can't return float and any other add can't return ints).

This commit is contained in:
Dummi26 2023-04-19 15:40:05 +02:00
parent 2293e9365c
commit 2ac19dcd00
5 changed files with 223 additions and 13 deletions

21
iterators.mers Normal file
View File

@ -0,0 +1,21 @@
fn map_string_to_int(list [string ...] func fn((string int))) {
// return a function that can be used as an iterator
() {
// this function will be called by the for loop
// whenever it wants to retrieve the next item in the collection.
// get the element
elem = &list.remove(0)
switch! elem {
// if the element was present, run the map function to convert it from a string to an int and return the result
[string] {
[func.run(elem.0)]
}
// if there are no more elements, return something that doesn't match.
[] []
}
}
}
for v ["1" "2" "5" "-10" ...].map_string_to_int((s string) s.parse_int().assume1("list contained strings that can't be parsed to an int!")) {
debug(v)
}

View File

@ -910,7 +910,76 @@ fn parse_single_type_adv(
match file.next() {
Some('(') => {
break 'parse_single_type if name.as_str() == "fn" {
todo!("fn types");
let mut fn_types = vec![];
loop {
file.skip_whitespaces();
match file.next() {
Some('(') => {
let mut args = vec![];
loop {
let (t, fn_args_closed) =
parse_type_adv(file, true)?;
args.push(t);
if fn_args_closed {
break;
}
}
let out = if let Some(v) = args.pop() {
v
} else {
VSingleType::Tuple(vec![]).to()
};
fn get_all_single_types(
types: &mut Vec<VType>,
) -> Vec<Vec<VSingleType>>
{
if types.is_empty() {
vec![]
} else if types.len() == 1 {
vec![types[0].types.clone()]
} else {
let last = types.pop().unwrap();
let o = get_all_single_types(types);
let mut out = Vec::with_capacity(
o.len() * last.types.len(),
);
for other in o {
for t in &last.types {
let mut vec = other.clone();
vec.push(t.clone());
out.push(vec);
}
}
types.push(last);
out
}
}
for t in get_all_single_types(&mut args) {
fn_types.push((t, out.clone()));
}
}
Some(')') => break,
Some(other) => {
eprintln!("Found char '{other}' in fn type when ')' or '(' was expected (will be treated as ')'). format is fn((input11 input12 output1) (input21 input22 output2))");
break;
}
None => {
return Err(ParseError {
err: ParseErrors::FoundEofInType,
location: err_start_of_single_type,
location_end: Some(*file.get_pos()),
context: vec![],
})
}
}
}
if in_fn_args {
if let Some(')') = file.peek() {
_ = file.next();
closed_bracket_in_fn_args = true;
}
}
VSingleType::Function(fn_types)
} else {
VSingleType::EnumVariantS(name, {
let po = parse_type_adv(file, true)?;

View File

@ -116,13 +116,14 @@ pub mod to_runnable {
InvalidType {
expected: VType,
found: VType,
problematic: Vec<VSingleType>,
problematic: VType,
},
CaseForceButTypeNotCovered(VType),
MatchConditionInvalidReturn(VType),
NotIndexableFixed(VType, usize),
WrongInputsForBuiltinFunction(BuiltinFunction, String, Vec<VType>),
WrongArgsForLibFunction(String, Vec<VType>),
ForLoopContainerHasNoInnerTypes,
}
impl Debug for ToRunnableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -144,7 +145,7 @@ pub mod to_runnable {
found,
problematic,
} => {
write!(f, "Invalid type: Expected {expected:?} but found {found:?}, which includes {problematic:?}, which is not covered.")
write!(f, "Invalid type: Expected {expected} but found {found}, which includes {problematic}, which is not covered.")
}
Self::CaseForceButTypeNotCovered(v) => write!(f, "Switch! statement, but not all types covered. Types to cover: {v}"),
Self::MatchConditionInvalidReturn(v) => write!(f, "match statement condition returned {v}, which is not necessarily a tuple of size 0 to 1."),
@ -163,6 +164,9 @@ pub mod to_runnable {
}
write!(f, ".")
}
Self::ForLoopContainerHasNoInnerTypes => {
write!(f, "For loop: container had no inner types, cannot iterate.")
}
}
}
}
@ -385,7 +389,7 @@ pub mod to_runnable {
return Err(ToRunnableError::InvalidType {
expected: func.input_types[i].clone(),
found: rarg,
problematic: out,
problematic: VType { types: out },
});
}
}
@ -446,7 +450,7 @@ pub mod to_runnable {
return Err(ToRunnableError::InvalidType {
expected: VSingleType::Bool.into(),
found: condition.out(),
problematic: out,
problematic: VType { types: out },
});
}
},
@ -462,9 +466,13 @@ pub mod to_runnable {
SStatementEnum::For(v, c, b) => {
let mut linfo = linfo.clone();
let container = statement(&c, ginfo, &mut linfo)?;
let inner = container.out().inner_types();
if inner.types.is_empty() {
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
}
linfo
.vars
.insert(v.clone(), (ginfo.vars, container.out().inner_types()));
.insert(v.clone(), (ginfo.vars, inner));
let for_loop_var = ginfo.vars;
ginfo.vars += 1;
let block = statement(&b, ginfo, &mut linfo)?;
@ -832,7 +840,7 @@ impl RStatementEnum {
// matching values also break with value from a for loop.
let c = c.run(vars, libs);
let mut vars = vars.clone();
let mut in_loop = |c| {
let in_loop = |vars: &mut Vec<Arc<Mutex<VData>>>, c| {
vars[*v] = Arc::new(Mutex::new(c));
b.run(&vars, libs)
};
@ -841,7 +849,9 @@ impl RStatementEnum {
match c.data {
VDataEnum::Int(v) => {
for i in 0..v {
if let Some(v) = in_loop(VDataEnum::Int(i).to()).data.matches() {
if let Some(v) =
in_loop(&mut vars, VDataEnum::Int(i).to()).data.matches()
{
oval = v;
break;
}
@ -849,9 +859,10 @@ impl RStatementEnum {
}
VDataEnum::String(v) => {
for ch in v.chars() {
if let Some(v) = in_loop(VDataEnum::String(ch.to_string()).to())
.data
.matches()
if let Some(v) =
in_loop(&mut vars, VDataEnum::String(ch.to_string()).to())
.data
.matches()
{
oval = v;
break;
@ -860,12 +871,22 @@ impl RStatementEnum {
}
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
for v in v {
if let Some(v) = in_loop(v).data.matches() {
if let Some(v) = in_loop(&mut vars, v).data.matches() {
oval = v;
break;
}
}
}
VDataEnum::Function(f) => loop {
if let Some(v) = f.run(&vars, libs).data.matches() {
if let Some(v) = in_loop(&mut vars, v).data.matches() {
oval = v;
break;
}
} else {
break;
}
},
_ => unreachable!(),
}
oval
@ -1063,7 +1084,17 @@ impl Display for VSingleType {
Ok(())
}
Self::List(t) => write!(f, "[{t} ...]"),
Self::Function(_) => write!(f, "FUNCTION"),
Self::Function(t) => {
write!(f, "fn(")?;
for (t, o) in t {
for t in t {
write!(f, "{t} ")?;
}
write!(f, "{o}")?;
}
write!(f, ")")?;
Ok(())
}
Self::Thread(_) => write!(f, "THREAD"),
Self::Reference(r) => write!(f, "&{r}"),
Self::EnumVariant(v, t) => write!(f, "{v}({t})"),

View File

@ -174,6 +174,21 @@ impl VSingleType {
Self::List(v) => v.types.clone(),
// NOTE: to make ints work in for loops
Self::Int => vec![Self::Int],
// for iterators in for loops: the match of the function's returned value make up the inner type
Self::Function(f) => {
// function that takes no inputs
if let Some(out) = f.iter().find_map(|(args, out)| {
if args.is_empty() {
Some(out.clone())
} else {
None
}
}) {
out.types
} else {
vec![]
}
}
_ => vec![],
}
}

74
mersrandr.mers Normal file
View File

@ -0,0 +1,74 @@
lib mers_libs/gui
// GUI for xrandr, because arandr doesn't let me change the framerates.
// [ WIP ]
base = gui_init()
set_title("MersRandr")
randr_output = run_command("xrandr")
switch! randr_output {
Err(string) {
println(randr_output.noenum())
}
[[]/int string string] {
lines = randr_output.1.regex(".*")
screen_name = ""
screen_resolutions = [["" ["" ...]] ...]
screens = [
[
screen_name
screen_resolutions
]
...]
&screen_resolutions.pop()
&screens.pop()
for line lines {
if line.starts_with("Screen ") {
// ignore
} else if line.starts_with(" ") {
// split at spaces (and ignore +*)
refresh_rates = line.regex("[^ +\\*]+").assume_no_enum()
resolution = &refresh_rates.remove(0).assume1()
print("{0} ::".format(resolution))
for rate refresh_rates {
print(" \"{0}\"".format(rate))
}
&screen_resolutions.push([resolution refresh_rates])
println("")
} else {
index = line.index_of(" ")
switch! index {
int {
if not(screen_name.len().eq(0)) {
&screens.push([screen_name screen_resolutions])
}
screen_resolutions = [ ...]
screen_name = line.substring(0 index)
println("> \"{0}\"".format(screen_name))
}
[] {}
}
}
}
if not(screen_name.len().eq(0)) {
&screens.push([screen_name screen_resolutions])
}
for screen screens {
println(screen.0)
gui_screen = base.gui_add(Row: [])
gui_name = gui_screen.gui_add(Text: screen.0)
for res screen.1 {
gui_resolution = gui_screen.gui_add(Button: res.0)
print(" ")
println(res.0)
for rate res.1 {
print(" ")
println(rate)
}
}
}
}
}