mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
fixed some bugs
This commit is contained in:
parent
efff8c1d70
commit
6da8a77304
16
README.md
16
README.md
@ -68,6 +68,20 @@ run() will return what the function returns while thread() will return a Thread
|
||||
|
||||
using switch! forces you to cover all possible types. Try removing the string or int case and see what happens!
|
||||
|
||||
### Reading /tmp/ and filtering for files/directories
|
||||
|
||||
for file fs_list("/tmp/") {
|
||||
list = file.fs_list()
|
||||
switch! list {
|
||||
[] {
|
||||
"\"{0}\" is a file".format(file).println()
|
||||
}
|
||||
[string] {
|
||||
"\"{0}\" is a directory".format(file).println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### Running a thread and awaiting it, passing arguments to the thread when starting it and sharing a variable because the thread's function captured it (useful for reporting progress, i.e. changing a float from 0.0 to 100.0 while downloading and using the main thread to animate a progress bar, then using .await() only when the float is set to 100 to avoid blocking)
|
||||
|
||||
print( "Starting" )
|
||||
@ -94,5 +108,3 @@ using switch! forces you to cover all possible types. Try removing the string or
|
||||
## Quirks
|
||||
|
||||
currently, f(a b c) is the same as a.f(b c). var.function(args) will use var as the function's first argument, moving all other arguments back. This removes the need for struct/class syntax. Simply declare a function scream(str string) { str.to_upper().print() } and you can now use var.scream() on all strings.
|
||||
|
||||
function(var) will break the parser, every argument has to be followed by a whitespace (space, tab, newline, ...). This will hopefully be fixed soon, but for now, function(var ) or just var.function() is the syntax that works.
|
||||
|
@ -65,6 +65,12 @@ impl File {
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn peek(&self) -> Option<char> {
|
||||
match self.chars.get(self.pos.current_char_index) {
|
||||
Some((_, c)) => Some(*c),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for File {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::script::{
|
||||
block::{
|
||||
to_runnable, to_runnable::ToRunnableError, RFunction, RScript, SBlock, SFunction,
|
||||
SStatement, SStatementEnum,
|
||||
to_runnable, to_runnable::ToRunnableError, RScript, SBlock, SFunction, SStatement,
|
||||
SStatementEnum,
|
||||
},
|
||||
value::{VData, VDataEnum, VSingleType, VType},
|
||||
value::{VDataEnum, VSingleType, VType},
|
||||
};
|
||||
|
||||
use super::file::File;
|
||||
@ -113,18 +113,30 @@ fn parse_statement_adv(
|
||||
) -> Result<SStatement, ParseError> {
|
||||
file.skip_whitespaces();
|
||||
let mut start = String::new();
|
||||
let out = match file.get_char(file.get_char_index()) {
|
||||
let out = match file.peek() {
|
||||
Some('{') => Some(SStatementEnum::Block(parse_block(file)?).into()),
|
||||
Some('[') => {
|
||||
file.next();
|
||||
let mut v = vec![];
|
||||
let mut list = false;
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
if let Some(']') = file.get_char(file.get_char_index()) {
|
||||
if let Some(']') = file.peek() {
|
||||
file.next();
|
||||
if file[file.get_char_index()..].starts_with("[]") {
|
||||
list = true;
|
||||
file.next();
|
||||
file.next();
|
||||
}
|
||||
break;
|
||||
}
|
||||
v.push(parse_statement(file)?);
|
||||
}
|
||||
Some(SStatementEnum::Tuple(v).into())
|
||||
Some(if list {
|
||||
SStatementEnum::List(v).into()
|
||||
} else {
|
||||
SStatementEnum::Tuple(v).into()
|
||||
})
|
||||
}
|
||||
Some('$') => {
|
||||
file.next();
|
||||
@ -163,12 +175,16 @@ fn parse_statement_adv(
|
||||
out
|
||||
} else {
|
||||
loop {
|
||||
match file.next() {
|
||||
match match file.peek() {
|
||||
Some(ch) if matches!(ch, '}' | ')' | '.') => Some(ch),
|
||||
_ => file.next(),
|
||||
} {
|
||||
Some('=') => {
|
||||
break parse_statement(file)?.output_to(start.trim().to_string());
|
||||
}
|
||||
Some(ch) if ch.is_whitespace() || matches!(ch, '}' | ')' | '.') => {
|
||||
if let Some('=') = file.get_char(file.get_char_index()) {
|
||||
Some(ch) if (ch.is_whitespace() || ch == '}' || ch == ')' || ch == '.') => {
|
||||
file.skip_whitespaces();
|
||||
if let Some('=') = file.peek() {
|
||||
continue;
|
||||
} else {
|
||||
let start = start.trim();
|
||||
@ -230,7 +246,14 @@ fn parse_statement_adv(
|
||||
}
|
||||
"switch" | "switch!" => {
|
||||
let force = start.ends_with("!");
|
||||
let switch_on_what = parse_statement(file)?;
|
||||
let mut switch_on_what = String::new();
|
||||
loop {
|
||||
match file.next() {
|
||||
None => break,
|
||||
Some(ch) if ch.is_whitespace() => break,
|
||||
Some(ch) => switch_on_what.push(ch),
|
||||
}
|
||||
}
|
||||
file.skip_whitespaces();
|
||||
if let Some('{') = file.next() {
|
||||
} else {
|
||||
@ -239,12 +262,17 @@ fn parse_statement_adv(
|
||||
let mut cases = vec![];
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
if let Some('}') = file.get_char(file.get_char_index()) {
|
||||
if let Some('}') = file.peek() {
|
||||
break;
|
||||
}
|
||||
cases.push((parse_type(file)?, parse_statement(file)?));
|
||||
}
|
||||
break SStatementEnum::Switch(switch_on_what, cases, force).into();
|
||||
break SStatementEnum::Switch(
|
||||
SStatementEnum::Variable(switch_on_what).into(),
|
||||
cases,
|
||||
force,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
"true" => {
|
||||
break SStatementEnum::Value(VDataEnum::Bool(true).to()).into()
|
||||
@ -350,7 +378,7 @@ fn parse_type_adv(file: &mut File, in_fn_args: bool) -> Result<(VType, bool), Pa
|
||||
break;
|
||||
}
|
||||
file.skip_whitespaces();
|
||||
match file.get_char(file.get_char_index()) {
|
||||
match file.peek() {
|
||||
Some('/') => (),
|
||||
_ => break,
|
||||
}
|
||||
@ -375,12 +403,15 @@ fn parse_single_type_adv(
|
||||
Some('[') => {
|
||||
let mut types = vec![];
|
||||
loop {
|
||||
types.push(parse_single_type(file)?.into());
|
||||
file.skip_whitespaces();
|
||||
match file.get_char(file.get_char_index()) {
|
||||
Some(']') => break,
|
||||
match file.peek() {
|
||||
Some(']') => {
|
||||
file.next();
|
||||
break;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
types.push(parse_single_type(file)?.into());
|
||||
}
|
||||
if types.len() == 1 {
|
||||
VSingleType::List(types.pop().unwrap())
|
||||
@ -391,6 +422,10 @@ fn parse_single_type_adv(
|
||||
Some(ch) => {
|
||||
let mut name = ch.to_string();
|
||||
loop {
|
||||
match file.peek() {
|
||||
Some(']') => break,
|
||||
_ => (),
|
||||
}
|
||||
match file.next() {
|
||||
Some(ch) if ch.is_whitespace() => break,
|
||||
Some(')') if in_fn_args => {
|
||||
|
@ -2,17 +2,15 @@
|
||||
// Types starting with S are directly parsed from Strings and unchecked. Types starting with T are type-checked templates for R-types. Types starting with R are runnable. S are converted to T after parsing is done, and T are converted to R whenever they need to run.
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use self::to_runnable::ToRunnableError;
|
||||
|
||||
use super::{
|
||||
builtins::BuiltinFunction,
|
||||
value::{VData, VDataEnum, VDataThreadEnum, VSingleType, VType},
|
||||
value::{VData, VDataEnum, VSingleType, VType},
|
||||
};
|
||||
|
||||
// Represents a block of code
|
||||
@ -60,6 +58,7 @@ impl SStatement {
|
||||
pub enum SStatementEnum {
|
||||
Value(VData),
|
||||
Tuple(Vec<SStatement>),
|
||||
List(Vec<SStatement>),
|
||||
Variable(String),
|
||||
FunctionCall(String, Vec<SStatement>),
|
||||
FunctionDefinition(Option<String>, SFunction),
|
||||
@ -94,11 +93,11 @@ pub mod to_runnable {
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::script::value::{VData, VDataEnum, VSingleType, VType};
|
||||
use crate::script::value::{VDataEnum, VSingleType, VType};
|
||||
|
||||
use super::{
|
||||
Am, BuiltinFunction, RBlock, RFunction, RScript, RStatement, RStatementEnum, SBlock,
|
||||
SFunction, SStatement, SStatementEnum,
|
||||
BuiltinFunction, RBlock, RFunction, RScript, RStatement, RStatementEnum, SBlock, SFunction,
|
||||
SStatement, SStatementEnum,
|
||||
};
|
||||
|
||||
pub enum ToRunnableError {
|
||||
@ -253,13 +252,17 @@ pub mod to_runnable {
|
||||
) -> Result<RStatement, ToRunnableError> {
|
||||
let mut statement = match &*s.statement {
|
||||
SStatementEnum::Value(v) => RStatementEnum::Value(v.clone()),
|
||||
SStatementEnum::Tuple(v) => {
|
||||
SStatementEnum::Tuple(v) | SStatementEnum::List(v) => {
|
||||
let mut w = Vec::with_capacity(v.len());
|
||||
for v in v {
|
||||
w.push(statement(v, ginfo, linfo)?);
|
||||
}
|
||||
if let SStatementEnum::List(_) = &*s.statement {
|
||||
RStatementEnum::List(w)
|
||||
} else {
|
||||
RStatementEnum::Tuple(w)
|
||||
}
|
||||
}
|
||||
SStatementEnum::Variable(v) => {
|
||||
if let Some(var) = linfo.vars.get(v) {
|
||||
RStatementEnum::Variable(var.0, var.1.clone())
|
||||
@ -376,7 +379,6 @@ pub mod to_runnable {
|
||||
let mut ncases = Vec::with_capacity(cases.len());
|
||||
for case in cases {
|
||||
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
|
||||
eprintln!("NCASE: {:#?}", ncases.last().unwrap().0);
|
||||
}
|
||||
let switch_on = statement(switch_on, ginfo, linfo)?;
|
||||
let switch_on_out = switch_on.out();
|
||||
@ -386,7 +388,6 @@ pub mod to_runnable {
|
||||
'force: {
|
||||
for (case_type, _) in ncases.iter() {
|
||||
if val_type.fits_in(&case_type).is_empty() {
|
||||
eprintln!("Breaking.");
|
||||
break 'force;
|
||||
}
|
||||
}
|
||||
@ -503,6 +504,7 @@ impl RStatement {
|
||||
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
|
||||
FunctionCall(Arc<RFunction>, Vec<RStatement>),
|
||||
BuiltinFunction(BuiltinFunction, Vec<RStatement>),
|
||||
@ -523,6 +525,16 @@ impl RStatementEnum {
|
||||
}
|
||||
VDataEnum::Tuple(w).to()
|
||||
}
|
||||
Self::List(v) => {
|
||||
let mut w = vec![];
|
||||
let mut out = VType { types: vec![] };
|
||||
for v in v {
|
||||
let val = v.run(vars);
|
||||
out = out | val.out();
|
||||
w.push(val);
|
||||
}
|
||||
VDataEnum::List(out, w).to()
|
||||
}
|
||||
Self::Variable(v, _) => vars[*v].lock().unwrap().clone(),
|
||||
Self::FunctionCall(func, args) => {
|
||||
for (i, input) in func.inputs.iter().enumerate() {
|
||||
@ -576,7 +588,7 @@ impl RStatementEnum {
|
||||
in_loop(VDataEnum::String(ch.to_string()).to())
|
||||
}
|
||||
}
|
||||
VDataEnum::Tuple(v) | VDataEnum::List(v) => {
|
||||
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
|
||||
for v in v {
|
||||
in_loop(v)
|
||||
}
|
||||
@ -603,7 +615,9 @@ impl RStatementEnum {
|
||||
pub fn out(&self) -> VType {
|
||||
match self {
|
||||
Self::Value(v) => v.out(),
|
||||
Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into(),
|
||||
Self::Tuple(v) | Self::List(v) => {
|
||||
VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into()
|
||||
}
|
||||
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.");
|
||||
@ -658,6 +672,7 @@ impl RScript {
|
||||
pub fn run(&self, args: Vec<String>) -> VData {
|
||||
let mut vars = Vec::with_capacity(self.vars);
|
||||
vars.push(am(VDataEnum::List(
|
||||
VSingleType::String.into(),
|
||||
args.into_iter()
|
||||
.map(|v| VDataEnum::String(v).to())
|
||||
.collect(),
|
||||
@ -744,6 +759,13 @@ impl Display for SStatementEnum {
|
||||
v.iter().map(|v| format!("{} ", v)).collect::<String>()
|
||||
)
|
||||
}
|
||||
SStatementEnum::List(v) => {
|
||||
write!(
|
||||
f,
|
||||
"[{} ...]",
|
||||
v.iter().map(|v| format!("{} ", v)).collect::<String>()
|
||||
)
|
||||
}
|
||||
SStatementEnum::Variable(v) => write!(f, "{v}"),
|
||||
SStatementEnum::FunctionCall(func, args) => {
|
||||
write!(f, "{func}(")?;
|
||||
@ -805,7 +827,7 @@ impl Display for VDataEnum {
|
||||
Self::Int(v) => write!(f, "{v}"),
|
||||
Self::Float(v) => write!(f, "{v}"),
|
||||
Self::String(v) => write!(f, "{v}"),
|
||||
Self::Tuple(v) | Self::List(v) => {
|
||||
Self::Tuple(v) | Self::List(_, v) => {
|
||||
write!(f, "[")?;
|
||||
for v in v {
|
||||
write!(f, "{v}")?;
|
||||
|
@ -26,9 +26,7 @@ impl VData {
|
||||
VDataEnum::Float(..) => VSingleType::Float,
|
||||
VDataEnum::String(..) => VSingleType::String,
|
||||
VDataEnum::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()),
|
||||
VDataEnum::List(v) => {
|
||||
VSingleType::List(v.iter().fold(VType { types: vec![] }, |a, b| a | b.out()))
|
||||
}
|
||||
VDataEnum::List(t, _) => VSingleType::List(t.clone()),
|
||||
VDataEnum::Function(f) => VSingleType::Function(f.in_types().clone(), {
|
||||
eprintln!("Warn: generalizing function return type, disregarding input types. might make the type checker think it can return types it can only return with different arguments as the ones that were actually provided.");
|
||||
f.out_all()
|
||||
@ -45,7 +43,7 @@ pub enum VDataEnum {
|
||||
Float(f64),
|
||||
String(String),
|
||||
Tuple(Vec<VData>),
|
||||
List(Vec<VData>),
|
||||
List(VType, Vec<VData>),
|
||||
Function(RFunction),
|
||||
Thread(VDataThread, VType),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user