diff --git a/dust-lang/src/built_in_function.rs b/dust-lang/src/built_in_function.rs index fb21fca..6673b51 100644 --- a/dust-lang/src/built_in_function.rs +++ b/dust-lang/src/built_in_function.rs @@ -92,7 +92,7 @@ impl BuiltInFunction { stdin().read_line(&mut input)?; - Ok(Some(Value::string(input))) + Ok(Some(Value::string(input.trim_end_matches('\n')))) } else { Err(BuiltInFunctionError::WrongNumberOfValueArguments) } diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index 8296754..25907d0 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -35,7 +35,7 @@ impl<'src> DustError<'src> { AnalyzerError::ExpectedIntegerFloatOrString { position, .. } => position, AnalyzerError::UnexpectedIdentifier { position, .. } => position, }, - VmError::ParseError(_) => todo!(), + VmError::ParseError(parse_error) => &parse_error.position(), VmError::ValueError { position, .. } => position, VmError::BuiltInFunctionCallError(_) => todo!(), VmError::ExpectedIdentifier { position } => position, @@ -44,6 +44,7 @@ impl<'src> DustError<'src> { VmError::ExpectedFunction { position, .. } => position, VmError::ExpectedList { position } => position, VmError::ExpectedValue { position } => position, + VmError::UndefinedIdentifier { position, .. } => position, }; let label = self.vm_error.to_string(); let message = Level::Error.title(title).snippet( diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs index e5b604a..cb42e5b 100644 --- a/dust-lang/src/parse.rs +++ b/dust-lang/src/parse.rs @@ -128,7 +128,13 @@ impl<'src> Parser<'src> { } fn next_token(&mut self) -> Result<(), ParseError> { - self.current = self.lexer.next_token(self.source)?; + self.current = + self.lexer + .next_token(self.source) + .map_err(|lex_error| ParseError::LexError { + error: lex_error, + position: self.current.1, + })?; Ok(()) } @@ -341,7 +347,10 @@ impl<'src> Parser<'src> { left_span, )) } - _ => Err(ParseError::UnexpectedToken(self.current.0.to_owned())), + _ => Err(ParseError::UnexpectedToken { + actual: self.current.0.to_owned(), + position: self.current.1, + }), } } @@ -359,18 +368,30 @@ impl<'src> Parser<'src> { #[derive(Debug, PartialEq, Clone)] pub enum ParseError { - LexError(LexError), + LexError { error: LexError, position: Span }, ExpectedClosingParenthesis { actual: TokenOwned, position: Span }, ExpectedClosingSquareBrace { actual: TokenOwned, position: Span }, ExpectedOpeningParenthesis { actual: TokenOwned, position: Span }, - UnexpectedToken(TokenOwned), + UnexpectedToken { actual: TokenOwned, position: Span }, +} + +impl ParseError { + pub fn position(&self) -> Span { + match self { + Self::LexError { position, .. } => *position, + Self::ExpectedClosingParenthesis { position, .. } => *position, + Self::ExpectedClosingSquareBrace { position, .. } => *position, + Self::ExpectedOpeningParenthesis { position, .. } => *position, + Self::UnexpectedToken { position, .. } => *position, + } + } } impl Error for ParseError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { - Self::LexError(error) => Some(error), + Self::LexError { error, .. } => Some(error), _ => None, } } @@ -379,7 +400,7 @@ impl Error for ParseError { impl Display for ParseError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - Self::LexError(error) => write!(f, "{}", error), + Self::LexError { error, .. } => write!(f, "{}", error), Self::ExpectedClosingParenthesis { actual, .. } => { write!(f, "Expected closing parenthesis, found {actual}",) } @@ -389,17 +410,11 @@ impl Display for ParseError { Self::ExpectedOpeningParenthesis { actual, .. } => { write!(f, "Expected opening parenthesis, found {actual}",) } - Self::UnexpectedToken(actual) => write!(f, "Unexpected token {actual}"), + Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"), } } } -impl From for ParseError { - fn from(v: LexError) -> Self { - Self::LexError(v) - } -} - #[cfg(test)] mod tests { use crate::Identifier; diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 0e3f955..90d7f13 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -131,6 +131,9 @@ impl Value { (ValueInner::Integer(left), ValueInner::Integer(right)) => { Ok(Value::integer(left.saturating_add(*right))) } + (ValueInner::String(left), ValueInner::String(right)) => { + Ok(Value::string(left.to_string() + right)) + } _ => Err(ValueError::CannotAdd(self.clone(), other.clone())), } } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index c3e167f..e5bb5c5 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -171,7 +171,16 @@ impl Vm { Ok(function.clone().call(None, value_parameters, variables)?) } - Statement::Identifier(_) => Ok(None), + Statement::Identifier(identifier) => { + if let Some(value) = variables.get(&identifier) { + Ok(Some(value.clone())) + } else { + Err(VmError::UndefinedIdentifier { + identifier, + position: node.position, + }) + } + } Statement::List(nodes) => { let values = nodes .into_iter() @@ -303,17 +312,37 @@ impl Vm { pub enum VmError { AnaylyzerError(AnalyzerError), ParseError(ParseError), - ValueError { error: ValueError, position: Span }, + ValueError { + error: ValueError, + position: Span, + }, // Anaylsis Failures // These should be prevented by running the analyzer before the VM BuiltInFunctionCallError(BuiltInFunctionError), - ExpectedIdentifier { position: Span }, - ExpectedIdentifierOrInteger { position: Span }, - ExpectedInteger { position: Span }, - ExpectedFunction { actual: Value, position: Span }, - ExpectedList { position: Span }, - ExpectedValue { position: Span }, + ExpectedIdentifier { + position: Span, + }, + ExpectedIdentifierOrInteger { + position: Span, + }, + ExpectedInteger { + position: Span, + }, + ExpectedFunction { + actual: Value, + position: Span, + }, + ExpectedList { + position: Span, + }, + ExpectedValue { + position: Span, + }, + UndefinedIdentifier { + identifier: Identifier, + position: Span, + }, } impl From for VmError { @@ -383,6 +412,16 @@ impl Display for VmError { Self::ExpectedValue { position } => { write!(f, "Expected a value at position: {:?}", position) } + Self::UndefinedIdentifier { + identifier, + position, + } => { + write!( + f, + "Undefined identifier: {} at position: {:?}", + identifier, position + ) + } } } }