diff --git a/src/interpreter.rs b/src/interpreter.rs index cdcf83f..ededc52 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,10 +1,11 @@ -use std::collections::HashMap; +use std::{collections::HashMap, rc::Rc}; use crate::{parser::{Expr, BinOpType, UnOpType, Ast, Stmt, parse}, lexer::lex}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Value { I64(i64), + Str(Rc), } pub struct Interpreter { @@ -50,6 +51,9 @@ impl Interpreter { match self.resolve_expr(condition) { Value::I64(val) if val == 0 => break, Value::I64(_) => (), + + Value::Str(text) if text.is_empty() => break, + Value::Str(_) => (), } // Execute loop body @@ -70,6 +74,7 @@ impl Interpreter { fn resolve_expr(&mut self, expr: &Expr) -> Value { match expr { Expr::I64(val) => Value::I64(*val), + Expr::Str(name) => Value::Str(name.clone()), Expr::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, &lhs, &rhs), Expr::UnOp(uo, val) => self.resolve_unop(uo, &val), Expr::Ident(name) => { @@ -118,7 +123,7 @@ impl Interpreter { BinOpType::Le => Value::I64(if lhs <= rhs { 1 } else { 0 }), BinOpType::Assign => unreachable!(), }, - // _ => panic!("Value types are not compatible"), + _ => panic!("Value types are not compatible"), } } @@ -128,6 +133,7 @@ impl Interpreter { Value::I64(val) => match uo { UnOpType::Neg => Value::I64(-val), } + _ => panic!("Invalid unary operation for type"), } } diff --git a/src/lexer.rs b/src/lexer.rs index 75b15d7..25c3961 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -7,6 +7,9 @@ pub enum Token { /// Integer literal (64-bit) I64(i64), + /// String literal ("Some string") + Str(String), + /// Left parenthesis ('(') LParen, @@ -180,6 +183,46 @@ impl<'a> Lexer<'a> { '}' => tokens.push(Token::RBrace), '$' => tokens.push(Token::Dollar), + '"' => { + let mut text = String::new(); + + let mut escape = false; + + // Do as long as a next char exists and it is not '"' + loop { + if escape { + escape = false; + + match self.next() { + Some('\\') => text.push('\\'), + Some('n') => text.push('\n'), + Some('r') => text.push('\r'), + Some('t') => text.push('\t'), + ch => panic!("Invalid string escape: '{:?}'", ch), + } + + } else { + match self.peek() { + Some('"') => { + self.next(); + break; + } + Some('\\') => { + self.next(); + escape = true; + } + None => panic!("String is never terminated (missing '\"')"), + + _ => text.push(self.next().unwrap()), + } + } + } + + + + tokens.push(Token::Str(text)); + } + 'a'..='z' | 'A'..='Z' | '_' => { let mut ident = String::from(ch); diff --git a/src/parser.rs b/src/parser.rs index ac51b42..5c492a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,4 @@ -use std::iter::Peekable; +use std::{iter::Peekable, rc::Rc}; use crate::lexer::Token; @@ -82,6 +82,8 @@ pub enum Stmt { pub enum Expr { /// Integer literal (64-bit) I64(i64), + /// String literal + Str(Rc), /// Identifier (variable name) Ident(String), /// Binary operation. Consists of type, left hand side and right hand side @@ -93,6 +95,7 @@ pub enum Expr { /* ## Grammar ### Expressions +LITERAL = I64 | Str expr_primary = LITERAL | IDENT | "(" expr ")" | "-" expr_primary expr_mul = expr_primary (("*" | "/" | "%") expr_primary)* expr_add = expr_mul (("+" | "-") expr_mul)* @@ -265,6 +268,8 @@ impl> Parser { match self.next() { Token::I64(val) => Expr::I64(val), + Token::Str(text) => Expr::Str(text.into()), + Token::Ident(name) => Expr::Ident(name), Token::LParen => {