diff --git a/dust-lang/src/built_in_function.rs b/dust-lang/src/built_in_function.rs index 39b5a72..6cfe361 100644 --- a/dust-lang/src/built_in_function.rs +++ b/dust-lang/src/built_in_function.rs @@ -12,6 +12,9 @@ use crate::{Type, Value}; /// Integrated function that can be called from Dust code. #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum BuiltInFunction { + // String tools + ToString, + // Integer and float tools IsEven, IsOdd, @@ -31,6 +34,7 @@ impl BuiltInFunction { BuiltInFunction::IsOdd => "is_odd", BuiltInFunction::Length => "length", BuiltInFunction::ReadLine => "read_line", + BuiltInFunction::ToString => "to_string", BuiltInFunction::WriteLine => "write_line", } } @@ -41,6 +45,17 @@ impl BuiltInFunction { value_arguments: Option>, ) -> Result, BuiltInFunctionError> { match self { + BuiltInFunction::ToString => { + if let Some(value_arguments) = value_arguments { + if value_arguments.len() == 1 { + Ok(Some(Value::string(value_arguments[0].to_string()))) + } else { + Err(BuiltInFunctionError::WrongNumberOfValueArguments) + } + } else { + Err(BuiltInFunctionError::WrongNumberOfValueArguments) + } + } BuiltInFunction::IsEven => { if let Some(value_arguments) = value_arguments { if value_arguments.len() == 1 { @@ -115,6 +130,7 @@ impl BuiltInFunction { pub fn expected_return_type(&self) -> Option { match self { + BuiltInFunction::ToString => Some(Type::String), BuiltInFunction::IsEven => Some(Type::Boolean), BuiltInFunction::IsOdd => Some(Type::Boolean), BuiltInFunction::Length => Some(Type::Integer), diff --git a/dust-lang/src/lex.rs b/dust-lang/src/lex.rs index a4ea50c..9dfaa88 100644 --- a/dust-lang/src/lex.rs +++ b/dust-lang/src/lex.rs @@ -404,6 +404,7 @@ impl Lexer { "is_odd" => Token::IsOdd, "length" => Token::Length, "read_line" => Token::ReadLine, + "to_string" => Token::ToString, "true" => Token::Boolean("true"), "while" => Token::While, "write_line" => Token::WriteLine, diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs index 9ad37c3..534a2a8 100644 --- a/dust-lang/src/parse.rs +++ b/dust-lang/src/parse.rs @@ -476,7 +476,12 @@ impl<'src> Parser<'src> { } } ( - Token::IsEven | Token::IsOdd | Token::Length | Token::ReadLine | Token::WriteLine, + Token::IsEven + | Token::IsOdd + | Token::Length + | Token::ReadLine + | Token::ToString + | Token::WriteLine, left_position, ) => { let function = match self.current.0 { @@ -484,6 +489,7 @@ impl<'src> Parser<'src> { Token::IsOdd => BuiltInFunction::IsOdd, Token::Length => BuiltInFunction::Length, Token::ReadLine => BuiltInFunction::ReadLine, + Token::ToString => BuiltInFunction::ToString, Token::WriteLine => BuiltInFunction::WriteLine, _ => unreachable!(), }; diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index eef143e..09a8e30 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -23,6 +23,7 @@ pub enum Token<'src> { IsOdd, Length, ReadLine, + ToString, While, WriteLine, @@ -90,6 +91,7 @@ impl<'src> Token<'src> { Token::Star => TokenOwned::Star, Token::Slash => TokenOwned::Slash, Token::String(text) => TokenOwned::String(text.to_string()), + Token::ToString => TokenOwned::ToString, Token::While => TokenOwned::While, Token::WriteLine => TokenOwned::WriteLine, } @@ -133,6 +135,7 @@ impl<'src> Token<'src> { Token::Semicolon => ";", Token::Star => "*", Token::Slash => "/", + Token::ToString => "to_string", Token::While => "while", Token::WriteLine => "write_line", } @@ -246,6 +249,7 @@ pub enum TokenOwned { IsOdd, Length, ReadLine, + ToString, While, WriteLine, @@ -284,14 +288,14 @@ impl Display for TokenOwned { TokenOwned::DoubleAmpersand => Token::DoubleAmpersand.fmt(f), TokenOwned::DoubleEqual => Token::DoubleEqual.fmt(f), TokenOwned::DoublePipe => Token::DoublePipe.fmt(f), - TokenOwned::Else => write!(f, "else"), + TokenOwned::Else => Token::Else.fmt(f), TokenOwned::Eof => Token::Eof.fmt(f), TokenOwned::Equal => Token::Equal.fmt(f), TokenOwned::Float(float) => write!(f, "{float}"), TokenOwned::Greater => Token::Greater.fmt(f), TokenOwned::GreaterOrEqual => Token::GreaterEqual.fmt(f), TokenOwned::Identifier(text) => write!(f, "{text}"), - TokenOwned::If => write!(f, "if"), + TokenOwned::If => Token::If.fmt(f), TokenOwned::Integer(integer) => write!(f, "{integer}"), TokenOwned::IsEven => Token::IsEven.fmt(f), TokenOwned::IsOdd => Token::IsOdd.fmt(f), @@ -313,6 +317,7 @@ impl Display for TokenOwned { TokenOwned::Star => Token::Star.fmt(f), TokenOwned::Slash => Token::Slash.fmt(f), TokenOwned::String(string) => write!(f, "{string}"), + TokenOwned::ToString => Token::ToString.fmt(f), TokenOwned::While => Token::While.fmt(f), TokenOwned::WriteLine => Token::WriteLine.fmt(f), } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 6bb166c..a4ff40e 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -660,6 +660,16 @@ impl Display for VmError { mod tests { use super::*; + #[test] + fn to_string() { + let input = "42.to_string()"; + + assert_eq!( + run(input, &mut Context::new()), + Ok(Some(Value::string("42".to_string()))) + ); + } + #[test] fn r#if() { let input = "if true { 1 }"; diff --git a/dust_examples/fizzbuzz.ds b/dust_examples/fizzbuzz.ds index e44083a..3eda4a7 100644 --- a/dust_examples/fizzbuzz.ds +++ b/dust_examples/fizzbuzz.ds @@ -11,7 +11,7 @@ while count <= 15 { } else if divides_by_5 { 'buzz' } else { - count as str + count.to_string() } write_line(output)