Implement String Literals

- String literals can be stored in variables, but are fully immutable
  and are not compatible with any operators
This commit is contained in:
Kai-Philipp Nosper 2022-02-02 19:38:28 +01:00
parent 8cf6177cbc
commit d8f5b876ac
5 changed files with 52 additions and 4 deletions

View File

@ -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<String>),
/// Variable
Var(String),
/// Binary operation. Consists of type, left hand side and right hand side

View File

@ -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<String>),
}
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),
}
}
}

View File

@ -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);

View File

@ -182,6 +182,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
// 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

View File

@ -5,6 +5,9 @@ pub enum Token {
/// Integer literal (64-bit)
I64(i64),
/// String literal
String(String),
/// Identifier (name for variables, functions, ...)
Ident(String),