added arrow syntax for forcing output types and added the "any" type (which is basically useless and will likely change in the future)

This commit is contained in:
mark 2023-06-04 21:33:35 +02:00
parent efe8a177dc
commit db0be51fa4
11 changed files with 142 additions and 54 deletions

View File

@ -1,8 +1,23 @@
# mers statements overview # Mers statements overview
This is the documentation for mers statements. This is the documentation for mers statements.
In code, statements are represented by `SStatement`, `SStatementEnum`, `RStatement`, and `RStatementEnum`. In code, statements are represented by `SStatement`, `SStatementEnum`, `RStatement`, and `RStatementEnum`.
## statement prefixes
A statement can be prefixed with any number of stars `*`. This is called dereferencing and turns a reference to a value into the value itself. Modifying the value after a dereference leaves the value the reference was pointing to untouched (the data will be cloned to achieve this).
A statement can also be prefixed with an arrow followed by the type the statement will have: `-> int/float 12`.
Although the statement will always return an `int`, mers will assume that it could also return a float.
If the statement's output doesn't fit in the forced type (`-> int "text"`), mers will generate an error.
In combination with functions, this is similar to rust's syntax:
fn my_func(a int, b int) -> int {
a + b
}
# Different statements
## Value ## Value
A statement that always returns a certain value: `10`, `"Hello, World"`, ... A statement that always returns a certain value: `10`, `"Hello, World"`, ...

View File

@ -0,0 +1,3 @@
fn plus(a int, b int) -> int { a + b }
10.plus(20).debug()

View File

@ -0,0 +1,13 @@
fn debug_any(val any) {
val.debug()
}
"something".debug_any()
fn just_return(val any) {
val
}.debug()
v := "text"
v.debug()
v.just_return().debug()

View File

@ -979,7 +979,7 @@ impl BuiltinFunction {
run_input_types.push(val.out_single()); run_input_types.push(val.out_single());
*var.lock().unwrap() = val; *var.lock().unwrap() = val;
} }
let out_type = f.out(&run_input_types); let out_type = f.out(&run_input_types, &info);
let info = Arc::clone(info); let info = Arc::clone(info);
let f = Arc::clone(f); let f = Arc::clone(f);
VDataEnum::Thread( VDataEnum::Thread(

View File

@ -5,7 +5,15 @@ use crate::parsing::{
parse::{self, ParseError, ScriptError}, parse::{self, ParseError, ScriptError},
}; };
use super::{code_runnable::RScript, val_data::VData}; use super::{code_parsed::SStatement, code_runnable::RScript, val_data::VData, val_type::VType};
// macro format is !(macro_type [...])
#[derive(Debug)]
pub enum Macro {
/// Compiles and executes the provided mers code at compile-time and inserts the value
StaticMers(VData),
}
pub fn parse_macro(file: &mut File) -> Result<Macro, MacroError> { pub fn parse_macro(file: &mut File) -> Result<Macro, MacroError> {
file.skip_whitespaces(); file.skip_whitespaces();
@ -63,12 +71,6 @@ fn parse_mers_code(file: &mut File) -> Result<RScript, MacroError> {
} }
} }
#[derive(Debug)]
pub enum Macro {
/// Compiles and executes the provided mers code at compile-time and inserts the value
StaticMers(VData),
}
impl Display for Macro { impl Display for Macro {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

View File

@ -83,11 +83,11 @@ impl SBlock {
#[derive(Debug)] #[derive(Debug)]
pub struct SFunction { pub struct SFunction {
pub inputs: Vec<(String, VType)>, pub inputs: Vec<(String, VType)>,
pub block: SBlock, pub statement: SStatement,
} }
impl SFunction { impl SFunction {
pub fn new(inputs: Vec<(String, VType)>, block: SBlock) -> Self { pub fn new(inputs: Vec<(String, VType)>, statement: SStatement) -> Self {
Self { inputs, block } Self { inputs, statement }
} }
} }
@ -268,8 +268,9 @@ impl FormatGs for SStatement {
} }
// output self // output self
if let Some(force_opt) = &self.force_output_type { if let Some(force_opt) = &self.force_output_type {
write!(f, " -> ")?; write!(f, "-> ")?;
force_opt.fmtgs(f, info, form, file)?; force_opt.fmtgs(f, info, form, file)?;
write!(f, " ")?;
} }
write!(f, "{}", "*".repeat(self.derefs))?; write!(f, "{}", "*".repeat(self.derefs))?;
self.statement.fmtgs(f, info, form, file)?; self.statement.fmtgs(f, info, form, file)?;
@ -293,14 +294,14 @@ impl FormatGs for SFunction {
write!(f, "(")?; write!(f, "(")?;
for (i, (name, t)) in self.inputs.iter().enumerate() { for (i, (name, t)) in self.inputs.iter().enumerate() {
if i > 0 { if i > 0 {
write!(f, " {name}")?; write!(f, " {name} ")?;
} else { } else {
write!(f, "{name} ")?; write!(f, "{name} ")?;
} }
t.fmtgs(f, info, form, file)?; t.fmtgs(f, info, form, file)?;
} }
write!(f, ") ")?; write!(f, ") ")?;
self.block.fmtgs(f, info, form, file) self.statement.fmtgs(f, info, form, file)
} }
} }

View File

@ -63,13 +63,13 @@ pub struct RFunction {
pub inputs: Vec<Arc<Mutex<VData>>>, pub inputs: Vec<Arc<Mutex<VData>>>,
pub input_types: Vec<VType>, pub input_types: Vec<VType>,
pub input_output_map: Vec<(Vec<VSingleType>, VType)>, pub input_output_map: Vec<(Vec<VSingleType>, VType)>,
pub block: RBlock, pub statement: RStatement,
} }
impl RFunction { impl RFunction {
pub fn run(&self, info: &GSInfo) -> VData { pub fn run(&self, info: &GSInfo) -> VData {
self.block.run(info) self.statement.run(info)
} }
pub fn out(&self, input_types: &Vec<VSingleType>) -> VType { pub fn out(&self, input_types: &Vec<VSingleType>, info: &GlobalScriptInfo) -> VType {
self.input_output_map self.input_output_map
.iter() .iter()
.find_map(|v| { .find_map(|v| {
@ -79,7 +79,7 @@ impl RFunction {
None None
} }
}) })
.expect("invalid args for function! possible issue with type-checker if this can be reached! feel free to report a bug.") .unwrap_or_else(|| self.statement.out(info))
} }
pub fn out_vt(&self, input_types: &Vec<VType>, info: &GlobalScriptInfo) -> VType { pub fn out_vt(&self, input_types: &Vec<VType>, info: &GlobalScriptInfo) -> VType {
let mut out = VType { types: vec![] }; let mut out = VType { types: vec![] };
@ -92,10 +92,16 @@ impl RFunction {
out = out | otype; out = out | otype;
} }
} }
if out.types.is_empty() {
// this can happen if we used the `any` type in our function signature,
// so in that case we just return the most broad type possible.
self.statement.out(info)
} else {
out out
} }
}
pub fn out_all(&self, info: &GlobalScriptInfo) -> VType { pub fn out_all(&self, info: &GlobalScriptInfo) -> VType {
self.block.out(info) self.statement.out(info)
} }
pub fn in_types(&self) -> &Vec<VType> { pub fn in_types(&self) -> &Vec<VType> {
&self.input_types &self.input_types

View File

@ -263,12 +263,12 @@ fn get_all_functions(
vartype.to() vartype.to()
} }
} }
// block is parsed multiple times (this is why we get duplicates in stderr): // the statement is parsed multiple times (this is why we get duplicates in stderr):
// - n times for the function args to generate the input-output map // - n times for the function args to generate the input-output map
// - 1 more time here, where the function args aren't single types // - 1 more time here, where the function args aren't single types
out.push(( out.push((
inputs.clone(), inputs.clone(),
block(&s.block, ginfo, linfo.clone())?.out(ginfo), statement(&s.statement, ginfo, &mut linfo.clone())?.out(ginfo),
)); ));
Ok(()) Ok(())
} }
@ -307,7 +307,7 @@ fn function(
inputs: input_vars, inputs: input_vars,
input_types, input_types,
input_output_map: all_outs, input_output_map: all_outs,
block: block(&s.block, ginfo, linfo)?, statement: statement(&s.statement, ginfo, &mut linfo.clone())?,
}) })
} }
@ -331,7 +331,11 @@ pub fn stypes(t: &mut VType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunna
} }
pub fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> { pub fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> {
match t { match t {
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String => (), VSingleType::Any
| VSingleType::Bool
| VSingleType::Int
| VSingleType::Float
| VSingleType::String => (),
VSingleType::Tuple(v) => { VSingleType::Tuple(v) => {
for t in v { for t in v {
stypes(t, ginfo)?; stypes(t, ginfo)?;
@ -398,7 +402,7 @@ fn statement_adv(
// eprintln!(" --> {}", t.0); // eprintln!(" --> {}", t.0);
// } // }
let mut state = match &*s.statement { let mut state = match &*s.statement {
SStatementEnum::Value(v) => RStatementEnum::Value(v.clone()), SStatementEnum::Value(v) => RStatementEnum::Value(v.clone()).to(),
SStatementEnum::Tuple(v) | SStatementEnum::List(v) => { SStatementEnum::Tuple(v) | SStatementEnum::List(v) => {
let mut w = Vec::with_capacity(v.len()); let mut w = Vec::with_capacity(v.len());
let mut prev = None; let mut prev = None;
@ -425,6 +429,7 @@ fn statement_adv(
} else { } else {
RStatementEnum::Tuple(w) RStatementEnum::Tuple(w)
} }
.to()
} }
SStatementEnum::Variable(v, is_ref) => { SStatementEnum::Variable(v, is_ref) => {
let existing_var = linfo.vars.get(v); let existing_var = linfo.vars.get(v);
@ -465,6 +470,7 @@ fn statement_adv(
} else { } else {
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone())); return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
} }
.to()
} }
SStatementEnum::FunctionCall(v, args) => { SStatementEnum::FunctionCall(v, args) => {
let mut rargs = Vec::with_capacity(args.len()); let mut rargs = Vec::with_capacity(args.len());
@ -553,6 +559,7 @@ fn statement_adv(
} }
} }
} }
.to(),
SStatementEnum::FunctionDefinition(name, f) => { SStatementEnum::FunctionDefinition(name, f) => {
let f = Arc::new(function(f, ginfo, linfo.clone())?); let f = Arc::new(function(f, ginfo, linfo.clone())?);
if let Some(name) = name { if let Some(name) = name {
@ -564,9 +571,9 @@ fn statement_adv(
linfo.fns.insert(name.clone(), vec![f]); linfo.fns.insert(name.clone(), vec![f]);
} }
} }
RStatementEnum::Value(VDataEnum::Function(f).to()) RStatementEnum::Value(VDataEnum::Function(f).to()).to()
} }
SStatementEnum::Block(b) => RStatementEnum::Block(block(&b, ginfo, linfo.clone())?), SStatementEnum::Block(b) => RStatementEnum::Block(block(&b, ginfo, linfo.clone())?).to(),
SStatementEnum::If(c, t, e) => RStatementEnum::If( SStatementEnum::If(c, t, e) => RStatementEnum::If(
{ {
let condition = statement(&c, ginfo, linfo)?; let condition = statement(&c, ginfo, linfo)?;
@ -591,8 +598,9 @@ fn statement_adv(
Some(v) => Some(statement(&v, ginfo, linfo)?), Some(v) => Some(statement(&v, ginfo, linfo)?),
None => None, None => None,
}, },
), )
SStatementEnum::Loop(c) => RStatementEnum::Loop(statement(&c, ginfo, linfo)?), .to(),
SStatementEnum::Loop(c) => RStatementEnum::Loop(statement(&c, ginfo, linfo)?).to(),
SStatementEnum::For(v, c, b) => { SStatementEnum::For(v, c, b) => {
let mut linfo = linfo.clone(); let mut linfo = linfo.clone();
let container = statement(&c, ginfo, &mut linfo)?; let container = statement(&c, ginfo, &mut linfo)?;
@ -603,7 +611,7 @@ fn statement_adv(
let assign_to = statement_adv(v, ginfo, &mut linfo, &mut Some((inner, &mut true)))?; let assign_to = statement_adv(v, ginfo, &mut linfo, &mut Some((inner, &mut true)))?;
let block = statement(&b, ginfo, &mut linfo)?; let block = statement(&b, ginfo, &mut linfo)?;
let o = RStatementEnum::For(assign_to, container, block); let o = RStatementEnum::For(assign_to, container, block);
o o.to()
} }
SStatementEnum::Switch(switch_on, cases, force) => { SStatementEnum::Switch(switch_on, cases, force) => {
@ -639,7 +647,7 @@ fn statement_adv(
})); }));
} }
} }
RStatementEnum::Switch(switch_on, ncases, *force) RStatementEnum::Switch(switch_on, ncases, *force).to()
} }
SStatementEnum::Match(cases) => { SStatementEnum::Match(cases) => {
let mut ncases: Vec<(RStatement, RStatement, RStatement)> = let mut ncases: Vec<(RStatement, RStatement, RStatement)> =
@ -667,13 +675,13 @@ fn statement_adv(
out_type = out_type | VSingleType::Tuple(vec![]).to(); out_type = out_type | VSingleType::Tuple(vec![]).to();
} }
RStatementEnum::Match(ncases) RStatementEnum::Match(ncases).to()
} }
SStatementEnum::IndexFixed(st, i) => { SStatementEnum::IndexFixed(st, i) => {
let st = statement(st, ginfo, linfo)?; let st = statement(st, ginfo, linfo)?;
if st.out(ginfo).get_always(*i, ginfo).is_some() { if st.out(ginfo).get_always(*i, ginfo).is_some() {
RStatementEnum::IndexFixed(st, *i) RStatementEnum::IndexFixed(st, *i).to()
} else { } else {
return Err(ToRunnableError::NotIndexableFixed(st.out(ginfo), *i)); return Err(ToRunnableError::NotIndexableFixed(st.out(ginfo), *i));
} }
@ -689,7 +697,8 @@ fn statement_adv(
} }
}, },
statement(s, ginfo, linfo)?, statement(s, ginfo, linfo)?,
), )
.to(),
SStatementEnum::TypeDefinition(name, t) => { SStatementEnum::TypeDefinition(name, t) => {
// insert to name map has to happen before stypes() // insert to name map has to happen before stypes()
ginfo ginfo
@ -698,13 +707,12 @@ fn statement_adv(
let mut t = t.to_owned(); let mut t = t.to_owned();
stypes(&mut t, ginfo)?; stypes(&mut t, ginfo)?;
ginfo.custom_types.push(t); ginfo.custom_types.push(t);
RStatementEnum::Value(VDataEnum::Tuple(vec![]).to()) RStatementEnum::Value(VDataEnum::Tuple(vec![]).to()).to()
} }
SStatementEnum::Macro(m) => match m { SStatementEnum::Macro(m) => match m {
Macro::StaticMers(val) => RStatementEnum::Value(val.clone()), Macro::StaticMers(val) => RStatementEnum::Value(val.clone()).to(),
}, },
} };
.to();
state.derefs = s.derefs; state.derefs = s.derefs;
// if force_output_type is set, verify that the real output type actually fits in the forced one. // if force_output_type is set, verify that the real output type actually fits in the forced one.
if let Some(force_opt) = &s.force_output_type { if let Some(force_opt) = &s.force_output_type {

View File

@ -18,6 +18,7 @@ pub struct VType {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum VSingleType { pub enum VSingleType {
Any,
Bool, Bool,
Int, Int,
Float, Float,
@ -37,7 +38,8 @@ impl VSingleType {
/// None => Cannot get, Some(t) => getting can return t or nothing /// None => Cannot get, Some(t) => getting can return t or nothing
pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> { pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool Self::Any
| Self::Bool
| Self::Int | Self::Int
| Self::Float | Self::Float
| Self::Function(..) | Self::Function(..)
@ -56,7 +58,8 @@ impl VSingleType {
} }
pub fn get_ref(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> { pub fn get_ref(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool Self::Any
| Self::Bool
| Self::Int | Self::Int
| Self::Float | Self::Float
| Self::Function(..) | Self::Function(..)
@ -76,7 +79,8 @@ impl VSingleType {
/// None => might not always return t, Some(t) => can only return t /// None => might not always return t, Some(t) => can only return t
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> { pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool Self::Any
| Self::Bool
| Self::Int | Self::Int
| Self::Float | Self::Float
| Self::String | Self::String
@ -95,7 +99,8 @@ impl VSingleType {
} }
pub fn get_always_ref(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> { pub fn get_always_ref(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool Self::Any
| Self::Bool
| Self::Int | Self::Int
| Self::Float | Self::Float
| Self::String | Self::String
@ -179,7 +184,12 @@ impl VType {
impl VSingleType { impl VSingleType {
pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> { pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, Self::Any
| Self::Bool
| Self::Int
| Self::Float
| Self::Function(..)
| Self::Thread(..) => None,
Self::String => Some(VSingleType::String.into()), Self::String => Some(VSingleType::String.into()),
Self::Tuple(t) => Some(t.iter().fold(VType { types: vec![] }, |a, b| a | b)), Self::Tuple(t) => Some(t.iter().fold(VType { types: vec![] }, |a, b| a | b)),
Self::List(t) => Some(t.clone()), Self::List(t) => Some(t.clone()),
@ -192,7 +202,12 @@ impl VSingleType {
} }
pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option<VType> { pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, Self::Any
| Self::Bool
| Self::Int
| Self::Float
| Self::Function(..)
| Self::Thread(..) => None,
Self::String => Some(VSingleType::String.into()), Self::String => Some(VSingleType::String.into()),
Self::Tuple(t) => Some( Self::Tuple(t) => Some(
t.iter() t.iter()
@ -378,7 +393,7 @@ impl VSingleType {
/// converts all Self::EnumVariantS to Self::EnumVariant /// converts all Self::EnumVariantS to Self::EnumVariant
pub fn enum_variants(&mut self, enum_variants: &mut HashMap<String, usize>) { pub fn enum_variants(&mut self, enum_variants: &mut HashMap<String, usize>) {
match self { match self {
Self::Bool | Self::Int | Self::Float | Self::String => (), Self::Any | Self::Bool | Self::Int | Self::Float | Self::String => (),
Self::Tuple(v) => { Self::Tuple(v) => {
for t in v { for t in v {
t.enum_variants(enum_variants); t.enum_variants(enum_variants);
@ -412,6 +427,8 @@ impl VSingleType {
} }
pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool { pub fn fits_in(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool {
let o = match (self, rhs) { let o = match (self, rhs) {
(_, Self::Any) => true,
(Self::Any, _) => false,
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b, info), (Self::Reference(r), Self::Reference(b)) => r.fits_in(b, info),
(Self::Reference(_), _) | (_, Self::Reference(_)) => false, (Self::Reference(_), _) | (_, Self::Reference(_)) => false,
(Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => { (Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => {
@ -526,6 +543,7 @@ impl FormatGs for VSingleType {
file: Option<&crate::parsing::file::File>, file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
match self { match self {
Self::Any => write!(f, "any"),
Self::Bool => write!(f, "bool"), Self::Bool => write!(f, "bool"),
Self::Int => write!(f, "int"), Self::Int => write!(f, "int"),
Self::Float => write!(f, "float"), Self::Float => write!(f, "float"),
@ -649,7 +667,7 @@ impl FormatGs for VType {
} }
t.fmtgs(f, info, form, file)?; t.fmtgs(f, info, form, file)?;
} }
Ok(()) write!(f, ",")
} }
} }
impl Display for VType { impl Display for VType {

View File

@ -390,6 +390,7 @@ impl ByteData for VType {
impl ByteDataA for VSingleType { impl ByteDataA for VSingleType {
fn as_byte_data(&self, vec: &mut Vec<u8>) { fn as_byte_data(&self, vec: &mut Vec<u8>) {
match self { match self {
Self::Any => vec.push(b'a'),
Self::Bool => vec.push(b'b'), Self::Bool => vec.push(b'b'),
Self::Int => vec.push(b'i'), Self::Int => vec.push(b'i'),
Self::Float => vec.push(b'f'), Self::Float => vec.push(b'f'),
@ -438,6 +439,7 @@ impl ByteData for VSingleType {
let mut switch_byte = [0u8]; let mut switch_byte = [0u8];
data.read_exact(&mut switch_byte)?; data.read_exact(&mut switch_byte)?;
Ok(match switch_byte[0] { Ok(match switch_byte[0] {
b'a' => Self::Any,
b'b' => Self::Bool, b'b' => Self::Bool,
b'i' => Self::Int, b'i' => Self::Int,
b'f' => Self::Float, b'f' => Self::Float,

View File

@ -192,7 +192,7 @@ pub fn parse_step_interpret(
"args".to_string(), "args".to_string(),
VSingleType::List(VSingleType::String.into()).to(), VSingleType::List(VSingleType::String.into()).to(),
)], )],
parse_block_advanced(file, Some(false), true, true, false)?, SStatementEnum::Block(parse_block_advanced(file, Some(false), false, true, false)?).to(),
); );
if ginfo.log.after_parse.log() { if ginfo.log.after_parse.log() {
ginfo.log.log(LogMsg::AfterParse( ginfo.log.log(LogMsg::AfterParse(
@ -543,6 +543,18 @@ pub mod implementation {
) -> Result<SStatement, ParseError> { ) -> Result<SStatement, ParseError> {
file.skip_whitespaces(); file.skip_whitespaces();
let err_start_of_statement = *file.get_pos(); let err_start_of_statement = *file.get_pos();
// force output type
let force_opt = if file[file.get_pos().current_char_index..].starts_with("->") {
file.next();
file.next();
file.skip_whitespaces();
let o = parse_type(file)?;
file.skip_whitespaces();
Some(o)
} else {
None
};
// derefs
let mut derefs = 0; let mut derefs = 0;
loop { loop {
if let Some('*') = file.peek() { if let Some('*') = file.peek() {
@ -836,6 +848,7 @@ pub mod implementation {
} }
}; };
out.derefs = derefs; out.derefs = derefs;
out.force_output_type = force_opt;
let err_end_of_original_statement = *file.get_pos(); let err_end_of_original_statement = *file.get_pos();
// special characters that can follow a statement (loop because these can be chained) // special characters that can follow a statement (loop because these can be chained)
loop { loop {
@ -1070,6 +1083,7 @@ pub mod implementation {
} else { } else {
loop { loop {
let mut arg_name = String::new(); let mut arg_name = String::new();
file.skip_whitespaces();
loop { loop {
let err_fn_arg_name_start = *file.get_pos(); let err_fn_arg_name_start = *file.get_pos();
match file.next() { match file.next() {
@ -1100,7 +1114,7 @@ pub mod implementation {
} }
} }
} }
Ok(SFunction::new(args, parse_block(file)?)) Ok(SFunction::new(args, parse_statement(file)?))
} }
pub(crate) fn parse_type(file: &mut File) -> Result<VType, ParseError> { pub(crate) fn parse_type(file: &mut File) -> Result<VType, ParseError> {
@ -1122,7 +1136,6 @@ pub mod implementation {
closed_fn_args = true; closed_fn_args = true;
break; break;
} }
file.skip_whitespaces();
match file.peek() { match file.peek() {
Some('/') => { Some('/') => {
file.next(); file.next();
@ -1132,8 +1145,15 @@ pub mod implementation {
file.next(); file.next();
break; break;
} }
Some(_) => break, Some(ch) if ch.is_whitespace() => break,
Some(ch) if ch == ',' => {
file.next();
break;
}
Some(ch) => {
eprintln!("[warn] stopped parsing type at character {ch} (unexpected character, moving on...)");
break;
}
None => break, None => break,
} }
} }
@ -1201,8 +1221,7 @@ pub mod implementation {
let mut name = ch.to_string(); let mut name = ch.to_string();
loop { loop {
match file.peek() { match file.peek() {
Some(']') => break, Some(']' | '/' | ',') => break,
Some('/') => break,
Some(')') if in_fn_args => { Some(')') if in_fn_args => {
file.next(); file.next();
closed_bracket_in_fn_args = true; closed_bracket_in_fn_args = true;
@ -1315,6 +1334,7 @@ pub mod implementation {
} }
} }
match name.trim().to_lowercase().as_str() { match name.trim().to_lowercase().as_str() {
"any" => VSingleType::Any,
"bool" => VSingleType::Bool, "bool" => VSingleType::Bool,
"int" => VSingleType::Int, "int" => VSingleType::Int,
"float" => VSingleType::Float, "float" => VSingleType::Float,