Implement lexing for boolean values
This commit is contained in:
parent
a60df0274c
commit
692f1145cd
@ -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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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";
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user