From 2a04a28f97b3a277de4d2175f33e6d305e09f475 Mon Sep 17 00:00:00 2001 From: Daniel M Date: Wed, 2 Feb 2022 19:38:28 +0100 Subject: [PATCH] Implement String Literals - String literals can be stored in variables, but are fully immutable and are not compatible with any operators --- src/ast.rs | 4 ++++ src/interpreter.rs | 11 +++++++---- src/lexer.rs | 35 +++++++++++++++++++++++++++++++++++ src/parser.rs | 3 +++ src/token.rs | 3 +++ 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 73c1ae0..83dc148 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + /// Types for binary operators #[derive(Debug, PartialEq, Eq, Clone)] pub enum BinOpType { @@ -78,6 +80,8 @@ pub enum UnOpType { pub enum Expression { /// Integer literal (64-bit) I64(i64), + /// String literal + String(Rc), /// Variable Var(String), /// Binary operation. Consists of type, left hand side and right hand side diff --git a/src/interpreter.rs b/src/interpreter.rs index 2c859aa..6066506 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,10 +1,11 @@ -use std::{collections::HashMap, fmt::Display}; +use std::{collections::HashMap, fmt::Display, rc::Rc}; use crate::{ast::{Expression, BinOpType, UnOpType, Ast, Statement, If}, parser::parse, lexer::lex}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Value { I64(i64), + String(Rc), } pub struct Interpreter { @@ -57,7 +58,7 @@ impl Interpreter { Statement::Print(expr) => { let result = self.resolve_expr(expr); - println!("{}", result); + print!("{}", result); } Statement::If(If {condition, body_true, body_false}) => { @@ -75,6 +76,7 @@ impl Interpreter { fn resolve_expr(&mut self, expr: &Expression) -> Value { match expr { Expression::I64(val) => Value::I64(*val), + Expression::String(text) => Value::String(text.clone()), Expression::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs), Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand), Expression::Var(name) => self.resolve_var(name), @@ -95,7 +97,7 @@ impl Interpreter { (Value::I64(val), UnOpType::Negate) => Value::I64(-val), (Value::I64(val), UnOpType::BNot) => Value::I64(!val), (Value::I64(val), UnOpType::LNot) => Value::I64(if val == 0 { 1 } else { 0 }), - // _ => panic!("Value type is not compatible with unary operation"), + _ => panic!("Value type is not compatible with unary operation"), } } @@ -142,7 +144,7 @@ impl Interpreter { BinOpType::Declare | BinOpType::Assign => unreachable!(), }, - // _ => panic!("Value types are not compatible"), + _ => panic!("Value types are not compatible"), } } } @@ -151,6 +153,7 @@ impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Value::I64(val) => write!(f, "{}", val), + Value::String(text) => write!(f, "{}", text), } } } diff --git a/src/lexer.rs b/src/lexer.rs index 25187c9..f02c95b 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -106,6 +106,41 @@ impl<'a> Lexer<'a> { tokens.push(Token::I64(sval.parse().unwrap())); } + '"' => { + // Opening " was consumed in match + + let mut text = String::new(); + + loop { + match self.peek() { + '"' => break, + '\0' => panic!("Encountered EoF while lexing string. Missing closing '\"'"), + _ => { + + match self.next() { + '\\' => { + match self.next() { + 'n' => text.push('\n'), + 'r' => text.push('\r'), + 't' => text.push('\t'), + '\\' => text.push('\\'), + '"' => text.push('"'), + ch => panic!("Invalid backslash escape: '{}'", ch), + } + } + ch => text.push(ch), + } + } + } + } + + // Consume closing " + self.next(); + + tokens.push(Token::String(text)) + + } + // Lex characters as identifier ch @ ('a'..='z' | 'A'..='Z' | '_') => { let mut ident = String::from(ch); diff --git a/src/parser.rs b/src/parser.rs index 503e924..171de60 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -182,6 +182,9 @@ impl> Parser { // Literal i64 Token::I64(val) => Expression::I64(val), + // Literal String + Token::String(text) => Expression::String(text.into()), + Token::Ident(name) => Expression::Var(name), // Parentheses grouping diff --git a/src/token.rs b/src/token.rs index 39746f9..19f3d3e 100644 --- a/src/token.rs +++ b/src/token.rs @@ -5,6 +5,9 @@ pub enum Token { /// Integer literal (64-bit) I64(i64), + /// String literal + String(String), + /// Identifier (name for variables, functions, ...) Ident(String),