mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
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:
parent
2293e9365c
commit
2ac19dcd00
21
iterators.mers
Normal file
21
iterators.mers
Normal 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)
|
||||
}
|
@ -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)?;
|
||||
|
@ -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})"),
|
||||
|
@ -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
74
mersrandr.mers
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user