Implement lexing for boolean values
This commit is contained in:
parent
a60df0274c
commit
692f1145cd
@ -35,6 +35,7 @@ pub enum Statement {
|
|||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
Add(Box<Node>, Box<Node>),
|
Add(Box<Node>, Box<Node>),
|
||||||
|
BuiltInValue(Box<Node>),
|
||||||
PropertyAccess(Box<Node>, Box<Node>),
|
PropertyAccess(Box<Node>, Box<Node>),
|
||||||
List(Vec<Node>),
|
List(Vec<Node>),
|
||||||
Multiply(Box<Node>, Box<Node>),
|
Multiply(Box<Node>, Box<Node>),
|
||||||
@ -50,6 +51,7 @@ impl Statement {
|
|||||||
match self {
|
match self {
|
||||||
Statement::Add(left, _) => left.statement.expected_type(variables),
|
Statement::Add(left, _) => left.statement.expected_type(variables),
|
||||||
Statement::Assign(_, _) => None,
|
Statement::Assign(_, _) => None,
|
||||||
|
Statement::BuiltInValue(reserved) => reserved.statement.expected_type(variables),
|
||||||
Statement::Constant(value) => Some(value.r#type(variables)),
|
Statement::Constant(value) => Some(value.r#type(variables)),
|
||||||
Statement::Identifier(identifier) => variables
|
Statement::Identifier(identifier) => variables
|
||||||
.get(identifier)
|
.get(identifier)
|
||||||
@ -58,8 +60,7 @@ impl Statement {
|
|||||||
Statement::Multiply(left, _) => left.statement.expected_type(variables),
|
Statement::Multiply(left, _) => left.statement.expected_type(variables),
|
||||||
Statement::PropertyAccess(_, _) => None,
|
Statement::PropertyAccess(_, _) => None,
|
||||||
Statement::ReservedIdentifier(reserved) => match reserved {
|
Statement::ReservedIdentifier(reserved) => match reserved {
|
||||||
ReservedIdentifier::IsEven => Some(Type::Boolean),
|
ReservedIdentifier::IsEven | ReservedIdentifier::IsOdd => Some(Type::Boolean),
|
||||||
ReservedIdentifier::IsOdd => Some(Type::Boolean),
|
|
||||||
ReservedIdentifier::Length => Some(Type::Integer),
|
ReservedIdentifier::Length => Some(Type::Integer),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -69,23 +70,24 @@ impl Statement {
|
|||||||
impl Display for Statement {
|
impl Display for Statement {
|
||||||
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 {
|
||||||
Statement::Assign(left, right) => write!(f, "{} = {}", left, right),
|
Statement::Assign(left, right) => write!(f, "{left} = {right}"),
|
||||||
Statement::Add(left, right) => write!(f, "{} + {}", left, right),
|
Statement::Add(left, right) => write!(f, "{left} + {right}"),
|
||||||
Statement::PropertyAccess(left, right) => write!(f, "{}.{}", left, right),
|
Statement::BuiltInValue(reserved) => write!(f, "{reserved}"),
|
||||||
|
Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"),
|
||||||
Statement::List(nodes) => {
|
Statement::List(nodes) => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
for (i, node) in nodes.iter().enumerate() {
|
for (i, node) in nodes.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}", node)?;
|
write!(f, "{node}")?;
|
||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
Statement::Multiply(left, right) => write!(f, "{} * {}", left, right),
|
Statement::Multiply(left, right) => write!(f, "{left} * {right}"),
|
||||||
Statement::Constant(value) => write!(f, "{}", value),
|
Statement::Constant(value) => write!(f, "{value}"),
|
||||||
Statement::Identifier(identifier) => write!(f, "{}", identifier),
|
Statement::Identifier(identifier) => write!(f, "{identifier}"),
|
||||||
Statement::ReservedIdentifier(identifier) => write!(f, "{}", identifier),
|
Statement::ReservedIdentifier(identifier) => write!(f, "{identifier}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@ impl Analyzer {
|
|||||||
|
|
||||||
self.analyze_node(right)?;
|
self.analyze_node(right)?;
|
||||||
}
|
}
|
||||||
|
Statement::BuiltInValue(node) => {
|
||||||
|
self.analyze_node(node)?;
|
||||||
|
}
|
||||||
Statement::Constant(_) => {}
|
Statement::Constant(_) => {}
|
||||||
Statement::Identifier(_) => {
|
Statement::Identifier(_) => {
|
||||||
return Err(AnalyzerError::UnexpectedIdentifier {
|
return Err(AnalyzerError::UnexpectedIdentifier {
|
||||||
|
@ -57,7 +57,7 @@ impl<'a> Lexer<'a> {
|
|||||||
let (token, span) = if let Some(c) = self.peek_char() {
|
let (token, span) = if let Some(c) = self.peek_char() {
|
||||||
match c {
|
match c {
|
||||||
'0'..='9' => self.lex_number()?,
|
'0'..='9' => self.lex_number()?,
|
||||||
'a'..='z' | 'A'..='Z' => self.lex_identifier()?,
|
'a'..='z' | 'A'..='Z' => self.lex_alphabetical()?,
|
||||||
'+' => {
|
'+' => {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
(Token::Plus, (self.position - 1, self.position))
|
(Token::Plus, (self.position - 1, self.position))
|
||||||
@ -124,6 +124,19 @@ impl<'a> Lexer<'a> {
|
|||||||
self.source[self.position..].chars().nth(1)
|
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.
|
/// Lex an integer or float token.
|
||||||
fn lex_number(&mut self) -> Result<(Token, Span), LexError> {
|
fn lex_number(&mut self) -> Result<(Token, Span), LexError> {
|
||||||
let start_pos = self.position;
|
let start_pos = self.position;
|
||||||
@ -167,7 +180,7 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lex an identifier token.
|
/// 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;
|
let start_pos = self.position;
|
||||||
|
|
||||||
while let Some(c) = self.peek_char() {
|
while let Some(c) = self.peek_char() {
|
||||||
@ -180,6 +193,8 @@ impl<'a> Lexer<'a> {
|
|||||||
|
|
||||||
let string = &self.source[start_pos..self.position];
|
let string = &self.source[start_pos..self.position];
|
||||||
let token = match string {
|
let token = match string {
|
||||||
|
"true" => Token::Boolean(true),
|
||||||
|
"false" => Token::Boolean(false),
|
||||||
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven),
|
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven),
|
||||||
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd),
|
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd),
|
||||||
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length),
|
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length),
|
||||||
@ -212,6 +227,26 @@ impl From<ParseIntError> for LexError {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn integer_property_access() {
|
fn integer_property_access() {
|
||||||
let input = "42.is_even";
|
let input = "42.is_even";
|
||||||
|
@ -6,6 +6,7 @@ use crate::Identifier;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
|
Boolean(bool),
|
||||||
Comma,
|
Comma,
|
||||||
Dot,
|
Dot,
|
||||||
Eof,
|
Eof,
|
||||||
@ -24,8 +25,11 @@ pub enum Token {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum ReservedIdentifier {
|
pub enum ReservedIdentifier {
|
||||||
|
// Number properties
|
||||||
IsEven,
|
IsEven,
|
||||||
IsOdd,
|
IsOdd,
|
||||||
|
|
||||||
|
// List properties
|
||||||
Length,
|
Length,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ impl Vm {
|
|||||||
variables: &mut HashMap<Identifier, Value>,
|
variables: &mut HashMap<Identifier, Value>,
|
||||||
) -> Result<Option<Value>, VmError> {
|
) -> Result<Option<Value>, VmError> {
|
||||||
match node.statement {
|
match node.statement {
|
||||||
|
Statement::BuiltInValue(node) => self.run_node(*node, variables),
|
||||||
Statement::Constant(value) => Ok(Some(value.clone())),
|
Statement::Constant(value) => Ok(Some(value.clone())),
|
||||||
Statement::Identifier(_) => Ok(None),
|
Statement::Identifier(_) => Ok(None),
|
||||||
Statement::ReservedIdentifier(_) => 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
|
// Anaylsis Failures
|
||||||
// These should be prevented by running the analyzer before the VM
|
// These should be prevented by running the analyzer before the VM
|
||||||
ExpectedIdentifier { position: Span },
|
ExpectedIdentifier {
|
||||||
ExpectedIdentifierOrInteger { position: Span },
|
position: Span,
|
||||||
ExpectedInteger { position: Span },
|
},
|
||||||
ExpectedList { position: Span },
|
ExpectedIdentifierOrInteger {
|
||||||
ExpectedValue { position: Span },
|
position: Span,
|
||||||
|
},
|
||||||
|
ExpectedInteger {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
ExpectedList {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
ExpectedDifferentReservedIdentifier {
|
||||||
|
position: Span,
|
||||||
|
expected: Vec<ReservedIdentifier>,
|
||||||
|
},
|
||||||
|
ExpectedValue {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParseError> for VmError {
|
impl From<ParseError> for VmError {
|
||||||
|
Loading…
Reference in New Issue
Block a user