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:
parent
8cf6177cbc
commit
d8f5b876ac
@ -1,3 +1,5 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Types for binary operators
|
/// Types for binary operators
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum BinOpType {
|
pub enum BinOpType {
|
||||||
@ -78,6 +80,8 @@ pub enum UnOpType {
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
/// Integer literal (64-bit)
|
/// Integer literal (64-bit)
|
||||||
I64(i64),
|
I64(i64),
|
||||||
|
/// String literal
|
||||||
|
String(Rc<String>),
|
||||||
/// Variable
|
/// Variable
|
||||||
Var(String),
|
Var(String),
|
||||||
/// Binary operation. Consists of type, left hand side and right hand side
|
/// Binary operation. Consists of type, left hand side and right hand side
|
||||||
|
|||||||
@ -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};
|
use crate::{ast::{Expression, BinOpType, UnOpType, Ast, Statement, If}, parser::parse, lexer::lex};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
I64(i64),
|
I64(i64),
|
||||||
|
String(Rc<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
@ -57,7 +58,7 @@ impl Interpreter {
|
|||||||
|
|
||||||
Statement::Print(expr) => {
|
Statement::Print(expr) => {
|
||||||
let result = self.resolve_expr(expr);
|
let result = self.resolve_expr(expr);
|
||||||
println!("{}", result);
|
print!("{}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::If(If {condition, body_true, body_false}) => {
|
Statement::If(If {condition, body_true, body_false}) => {
|
||||||
@ -75,6 +76,7 @@ impl Interpreter {
|
|||||||
fn resolve_expr(&mut self, expr: &Expression) -> Value {
|
fn resolve_expr(&mut self, expr: &Expression) -> Value {
|
||||||
match expr {
|
match expr {
|
||||||
Expression::I64(val) => Value::I64(*val),
|
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::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs),
|
||||||
Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand),
|
Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand),
|
||||||
Expression::Var(name) => self.resolve_var(name),
|
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::Negate) => Value::I64(-val),
|
||||||
(Value::I64(val), UnOpType::BNot) => Value::I64(!val),
|
(Value::I64(val), UnOpType::BNot) => Value::I64(!val),
|
||||||
(Value::I64(val), UnOpType::LNot) => Value::I64(if val == 0 { 1 } else { 0 }),
|
(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!(),
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Value::I64(val) => write!(f, "{}", val),
|
Value::I64(val) => write!(f, "{}", val),
|
||||||
|
Value::String(text) => write!(f, "{}", text),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/lexer.rs
35
src/lexer.rs
@ -106,6 +106,41 @@ impl<'a> Lexer<'a> {
|
|||||||
tokens.push(Token::I64(sval.parse().unwrap()));
|
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
|
// Lex characters as identifier
|
||||||
ch @ ('a'..='z' | 'A'..='Z' | '_') => {
|
ch @ ('a'..='z' | 'A'..='Z' | '_') => {
|
||||||
let mut ident = String::from(ch);
|
let mut ident = String::from(ch);
|
||||||
|
|||||||
@ -182,6 +182,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
// Literal i64
|
// Literal i64
|
||||||
Token::I64(val) => Expression::I64(val),
|
Token::I64(val) => Expression::I64(val),
|
||||||
|
|
||||||
|
// Literal String
|
||||||
|
Token::String(text) => Expression::String(text.into()),
|
||||||
|
|
||||||
Token::Ident(name) => Expression::Var(name),
|
Token::Ident(name) => Expression::Var(name),
|
||||||
|
|
||||||
// Parentheses grouping
|
// Parentheses grouping
|
||||||
|
|||||||
@ -5,6 +5,9 @@ pub enum Token {
|
|||||||
/// Integer literal (64-bit)
|
/// Integer literal (64-bit)
|
||||||
I64(i64),
|
I64(i64),
|
||||||
|
|
||||||
|
/// String literal
|
||||||
|
String(String),
|
||||||
|
|
||||||
/// Identifier (name for variables, functions, ...)
|
/// Identifier (name for variables, functions, ...)
|
||||||
Ident(String),
|
Ident(String),
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user