aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-11-14 19:31:48 +0100
committerMel <einebeere@gmail.com>2021-11-14 19:31:48 +0100
commit98ac2e8f26ff4d90c37bb9c9536e9eb14e31efb4 (patch)
treef7e4b47cd4d8a370597267f8f1819e874c5aacce
parent514ceb979c4ce79bfee2234cf981292ded714f66 (diff)
downloadrabbithole-98ac2e8f26ff4d90c37bb9c9536e9eb14e31efb4.tar.zst
rabbithole-98ac2e8f26ff4d90c37bb9c9536e9eb14e31efb4.zip
Parse and walk str embeds.
-rw-r--r--src/interpret/walker.rs17
-rw-r--r--src/lex/lexer.rs15
-rw-r--r--src/parse/ast/expression.rs17
-rw-r--r--src/parse/ast/nodes.rs22
-rw-r--r--src/parse/parser.rs34
5 files changed, 87 insertions, 18 deletions
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 471da89..68dc388 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
use crate::parse::ast::{
expression::Expression,
- nodes::{BinaryOperator as BinOp, BlockNode, SimpleLiteral, UnaryOperator as UnOp},
+ nodes::{BinaryOperator as BinOp, BlockNode, SimpleLiteral, StrPart, UnaryOperator as UnOp},
statement::Statement,
Program,
};
@@ -140,13 +140,26 @@ impl Walker {
let value = match token {
SimpleLiteral::Int(int) => Value::Int(*int as i64),
SimpleLiteral::Float(float) => Value::Float(*float as f64),
- SimpleLiteral::Str(string) => Value::Str(string.clone()),
SimpleLiteral::Bool(bool) => Value::Bool(*bool),
};
Ok(value)
}
Expression::Block(block) => self.walk_block(block.as_ref()),
+ Expression::StrLiteral(node) => {
+ let mut buffer = String::new();
+
+ for part in &node.parts {
+ match part {
+ StrPart::Literal(literal) => buffer.push_str(literal),
+ StrPart::Embed(embed) => {
+ buffer.push_str(&self.walk_expression(embed)?.to_string())
+ }
+ };
+ }
+
+ Ok(Value::Str(buffer))
+ }
Expression::FnLiteral(fn_node) => {
let node = fn_node.as_ref().clone();
Ok(Value::Fn(Rc::new(RefCell::new(node))))
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index 6467f5c..b6633d4 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -247,15 +247,19 @@ impl<'s> Lexer<'s> {
let mut nest_level = 0;
// Finish the last string part
- self.preempted.push_back(Token {
- location: location_str,
- variant: TokenVariant::Str(str_buffer),
- });
+ if !str_buffer.is_empty() {
+ self.preempted.push_back(Token {
+ location: location_str,
+ variant: TokenVariant::Str(str_buffer),
+ });
+ }
str_buffer = String::new();
// Build embed
let location_embed = self.location;
let mut embed_buffer = String::new();
+ embed_buffer.push(c);
+
loop {
// TOOD: Same as above
let c = self.advance().expect("Expected Str embed to be closed");
@@ -263,8 +267,7 @@ impl<'s> Lexer<'s> {
nest_level += 1;
} else if c == '}' {
if nest_level <= 0 {
- // Remove last '}' of embed
- self.advance().unwrap();
+ embed_buffer.push(c);
location_str = self.location;
break;
} else {
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index b2b9678..d119a71 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -1,8 +1,10 @@
use std::fmt::{self, Display, Formatter};
+use crate::parse::ast::nodes::StrPart;
+
use super::nodes::{
ArrayAccessNode, ArrayNode, BinaryOperator, BlockNode, CallNode, FnNode, Identifier, IfNode,
- LoopNode, MemberAccessNode, SimpleLiteral, UnaryOperator,
+ LoopNode, MemberAccessNode, SimpleLiteral, StrNode, UnaryOperator,
};
#[derive(Debug, Clone)]
@@ -23,6 +25,7 @@ pub enum Expression {
Block(Box<BlockNode>),
If(Box<IfNode>),
Loop(Box<LoopNode>),
+ StrLiteral(Box<StrNode>),
FnLiteral(Box<FnNode>),
ArrayLiteral(ArrayNode),
SimpleLiteral(SimpleLiteral),
@@ -82,6 +85,18 @@ impl Expression {
Expression::Block(block) => {
Self::block_fmt(f, block, depth + 1)?;
}
+ Expression::StrLiteral(node) => {
+ writeln!(f, "{}Str:", pad)?;
+ for (i, statement) in node.parts.iter().enumerate() {
+ writeln!(f, "{}- {}:", pad, i)?;
+ match statement {
+ StrPart::Literal(literal) => {
+ writeln!(f, "{}{}", " ".repeat(depth + 1), literal.clone())
+ }
+ StrPart::Embed(block) => block.nested_fmt(f, depth + 1),
+ }?;
+ }
+ }
Expression::FnLiteral(node) => {
write!(f, "{}Fn (", pad)?;
diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs
index 2bf3f17..c4bb1e8 100644
--- a/src/parse/ast/nodes.rs
+++ b/src/parse/ast/nodes.rs
@@ -64,7 +64,6 @@ impl UnaryOperator {
pub enum SimpleLiteral {
Int(u32),
Float(f32),
- Str(String),
Bool(bool),
}
@@ -73,7 +72,6 @@ impl SimpleLiteral {
match token.variant {
Int(int) => Self::Int(int),
Float(float) => Self::Float(float),
- Str(string) => Self::Str(string),
KeywordTrue => Self::Bool(true),
KeywordFalse => Self::Bool(false),
_ => panic!("Can't create literal from '{:?}'.", token.variant),
@@ -110,14 +108,20 @@ pub struct MemberAccessNode {
}
#[derive(Debug, Clone)]
-pub struct FnNode {
- pub header: FnHeader,
- pub body: BlockNode,
+pub struct StrNode {
+ pub parts: Vec<StrPart>,
}
#[derive(Debug, Clone)]
-pub struct ArrayNode {
- pub elements: Vec<Expression>,
+pub enum StrPart {
+ Literal(String),
+ Embed(Expression)
+}
+
+#[derive(Debug, Clone)]
+pub struct FnNode {
+ pub header: FnHeader,
+ pub body: BlockNode,
}
#[derive(Debug, Clone)]
@@ -128,6 +132,10 @@ pub struct FnHeader {
}
#[derive(Debug, Clone)]
+pub struct ArrayNode {
+ pub elements: Vec<Expression>,
+}
+#[derive(Debug, Clone)]
pub struct IfNode {
pub conditionals: Vec<ConditionalBlock>,
pub else_block: Option<BlockNode>,
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 6b0a785..5a09a8f 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,11 +1,12 @@
use super::ast::expression::Expression;
-use super::ast::nodes::{ArrayNode, LoopNode, UnaryOperator};
+use super::ast::nodes::{ArrayNode, LoopNode, StrNode, UnaryOperator};
use super::ast::statement::Statement;
use super::ast::Program;
+use crate::lex::lexer::Lexer;
use crate::lex::token::TokenVariant::*;
use crate::parse::ast::nodes::{
ArrayAccessNode, BinaryOperator, BlockNode, CallNode, ConditionalBlock, FnHeader, FnNode,
- IfNode, MemberAccessNode, SimpleLiteral, TypedIdentifier,
+ IfNode, MemberAccessNode, SimpleLiteral, StrPart, TypedIdentifier,
};
use crate::{check, consume, consume_if, inner, lex::token::Token};
use anyhow::{anyhow, Result};
@@ -267,6 +268,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
self.tokens.next().unwrap(),
Ident
))),
+ StrOpen => Ok(Expression::StrLiteral(Box::new(self.str()?))),
GroupOpen => Ok(Expression::Group(Box::new(self.group()?))),
BlockOpen => Ok(Expression::Block(Box::new(self.generic_block()?))),
ArrayOpen => Ok(Expression::ArrayLiteral(self.array()?)),
@@ -303,6 +305,34 @@ impl<T: Iterator<Item = Token>> Parser<T> {
Ok(ArrayNode { elements })
}
+ fn str(&mut self) -> Result<StrNode> {
+ let mut parts = Vec::new();
+
+ consume!(self, StrOpen)?;
+
+ loop {
+ let token = self.tokens.next().expect("Unclosed str.");
+
+ let part = match token.variant {
+ Str(literal) => StrPart::Literal(literal),
+ StrEmbed(code) => {
+ let embed_lexer = Lexer::new(&code);
+ let mut embed_parser = Parser::new(embed_lexer);
+
+ let node = embed_parser.expression()?;
+
+ StrPart::Embed(node)
+ }
+ StrClose => break,
+ _ => unreachable!(),
+ };
+
+ parts.push(part);
+ }
+
+ Ok(StrNode { parts })
+ }
+
fn function(&mut self) -> Result<FnNode> {
consume!(self, KeywordFn)?;
let token = self.tokens.next().expect("Expected function header.");