Implement lexing for boolean values

This commit is contained in:
Jeff 2024-08-07 10:41:27 -04:00
parent a60df0274c
commit 692f1145cd
5 changed files with 86 additions and 17 deletions

View File

@ -35,6 +35,7 @@ pub enum Statement {
// Expressions
Add(Box<Node>, Box<Node>),
BuiltInValue(Box<Node>),
PropertyAccess(Box<Node>, Box<Node>),
List(Vec<Node>),
Multiply(Box<Node>, Box<Node>),
@ -50,6 +51,7 @@ impl Statement {
match self {
Statement::Add(left, _) => left.statement.expected_type(variables),
Statement::Assign(_, _) => None,
Statement::BuiltInValue(reserved) => reserved.statement.expected_type(variables),
Statement::Constant(value) => Some(value.r#type(variables)),
Statement::Identifier(identifier) => variables
.get(identifier)
@ -58,8 +60,7 @@ impl Statement {
Statement::Multiply(left, _) => left.statement.expected_type(variables),
Statement::PropertyAccess(_, _) => None,
Statement::ReservedIdentifier(reserved) => match reserved {
ReservedIdentifier::IsEven => Some(Type::Boolean),
ReservedIdentifier::IsOdd => Some(Type::Boolean),
ReservedIdentifier::IsEven | ReservedIdentifier::IsOdd => Some(Type::Boolean),
ReservedIdentifier::Length => Some(Type::Integer),
},
}
@ -69,23 +70,24 @@ impl Statement {
impl Display for Statement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Statement::Assign(left, right) => write!(f, "{} = {}", left, right),
Statement::Add(left, right) => write!(f, "{} + {}", left, right),
Statement::PropertyAccess(left, right) => write!(f, "{}.{}", left, right),
Statement::Assign(left, right) => write!(f, "{left} = {right}"),
Statement::Add(left, right) => write!(f, "{left} + {right}"),
Statement::BuiltInValue(reserved) => write!(f, "{reserved}"),
Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"),
Statement::List(nodes) => {
write!(f, "[")?;
for (i, node) in nodes.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", node)?;
write!(f, "{node}")?;
}
write!(f, "]")
}
Statement::Multiply(left, right) => write!(f, "{} * {}", left, right),
Statement::Constant(value) => write!(f, "{}", value),
Statement::Identifier(identifier) => write!(f, "{}", identifier),
Statement::ReservedIdentifier(identifier) => write!(f, "{}", identifier),
Statement::Multiply(left, right) => write!(f, "{left} * {right}"),
Statement::Constant(value) => write!(f, "{value}"),
Statement::Identifier(identifier) => write!(f, "{identifier}"),
Statement::ReservedIdentifier(identifier) => write!(f, "{identifier}"),
}
}
}

View File

@ -40,6 +40,9 @@ impl Analyzer {
self.analyze_node(right)?;
}
Statement::BuiltInValue(node) => {
self.analyze_node(node)?;
}
Statement::Constant(_) => {}
Statement::Identifier(_) => {
return Err(AnalyzerError::UnexpectedIdentifier {

View File

@ -57,7 +57,7 @@ impl<'a> Lexer<'a> {
let (token, span) = if let Some(c) = self.peek_char() {
match c {
'0'..='9' => self.lex_number()?,
'a'..='z' | 'A'..='Z' => self.lex_identifier()?,
'a'..='z' | 'A'..='Z' => self.lex_alphabetical()?,
'+' => {
self.position += 1;
(Token::Plus, (self.position - 1, self.position))
@ -124,6 +124,19 @@ impl<'a> Lexer<'a> {
self.source[self.position..].chars().nth(1)
}
fn peek_until_whitespace(&self) -> Option<&str> {
let start = self.position;
let end = self.source[self.position..]
.find(char::is_whitespace)
.map(|i| i + start);
if let Some(end) = end {
Some(&self.source[start..end])
} else {
None
}
}
/// Lex an integer or float token.
fn lex_number(&mut self) -> Result<(Token, Span), LexError> {
let start_pos = self.position;
@ -167,7 +180,7 @@ impl<'a> Lexer<'a> {
}
/// Lex an identifier token.
fn lex_identifier(&mut self) -> Result<(Token, Span), LexError> {
fn lex_alphabetical(&mut self) -> Result<(Token, Span), LexError> {
let start_pos = self.position;
while let Some(c) = self.peek_char() {
@ -180,6 +193,8 @@ impl<'a> Lexer<'a> {
let string = &self.source[start_pos..self.position];
let token = match string {
"true" => Token::Boolean(true),
"false" => Token::Boolean(false),
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven),
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd),
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length),
@ -212,6 +227,26 @@ impl From<ParseIntError> for LexError {
mod tests {
use super::*;
#[test]
fn r#true() {
let input = "true";
assert_eq!(
lex(input),
Ok(vec![(Token::Boolean(true), (0, 4)), (Token::Eof, (4, 4)),])
)
}
#[test]
fn r#false() {
let input = "false";
assert_eq!(
lex(input),
Ok(vec![(Token::Boolean(false), (0, 5)), (Token::Eof, (5, 5))])
)
}
#[test]
fn integer_property_access() {
let input = "42.is_even";

View File

@ -6,6 +6,7 @@ use crate::Identifier;
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
Boolean(bool),
Comma,
Dot,
Eof,
@ -24,8 +25,11 @@ pub enum Token {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ReservedIdentifier {
// Number properties
IsEven,
IsOdd,
// List properties
Length,
}

View File

@ -42,6 +42,7 @@ impl Vm {
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
match node.statement {
Statement::BuiltInValue(node) => self.run_node(*node, variables),
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => Ok(None),
Statement::ReservedIdentifier(_) => Ok(None),
@ -143,6 +144,16 @@ impl Vm {
});
}
}
_ => {
return Err(VmError::ExpectedDifferentReservedIdentifier {
position: right_span,
expected: vec![
ReservedIdentifier::IsEven,
ReservedIdentifier::IsOdd,
ReservedIdentifier::Length,
],
})
}
}
}
@ -170,11 +181,25 @@ pub enum VmError {
// Anaylsis Failures
// These should be prevented by running the analyzer before the VM
ExpectedIdentifier { position: Span },
ExpectedIdentifierOrInteger { position: Span },
ExpectedInteger { position: Span },
ExpectedList { position: Span },
ExpectedValue { position: Span },
ExpectedIdentifier {
position: Span,
},
ExpectedIdentifierOrInteger {
position: Span,
},
ExpectedInteger {
position: Span,
},
ExpectedList {
position: Span,
},
ExpectedDifferentReservedIdentifier {
position: Span,
expected: Vec<ReservedIdentifier>,
},
ExpectedValue {
position: Span,
},
}
impl From<ParseError> for VmError {