about summary refs log tree commit diff
diff options
context:
space:
mode:
-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.");