diff --git a/grimoire/src/parser/span.rs b/grimoire/src/parser/span.rs
index ae08a5fff924cca8609d0eddf086aba0ded5dbe1..74a74c1a52af32665b797512a6955ed27c6c2c3a 100644
--- a/grimoire/src/parser/span.rs
+++ b/grimoire/src/parser/span.rs
@@ -1,5 +1,5 @@
 use crate::ast::Location;
-use nom::{Compare, Input, Offset as _};
+use nom::{Compare, FindSubstring, Input, Offset as _};
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Span<'a> {
@@ -135,3 +135,9 @@ impl Compare<&str> for Span<'_> {
         self.fragment().compare_no_case(t)
     }
 }
+
+impl FindSubstring<&str> for Span<'_> {
+    fn find_substring(&self, substr: &str) -> Option<usize> {
+        todo!()
+    }
+}
diff --git a/grimoire/src/parser/utils.rs b/grimoire/src/parser/utils.rs
index ee5d028502b489cae41a4fdd7c6aa13f7075ed89..e528b9c3e93db3cd56cfb11645c6ee59c5a6b4a0 100644
--- a/grimoire/src/parser/utils.rs
+++ b/grimoire/src/parser/utils.rs
@@ -4,8 +4,14 @@ use crate::{
 };
 use nom::{
     Parser,
-    bytes::complete::tag,
-    character::complete::{multispace0, multispace1},
+    branch::alt,
+    bytes::{
+        complete::{tag, take_while_m_n},
+        take_until,
+    },
+    character::complete::{char, digit1, multispace0, multispace1},
+    combinator::{peek, value, verify},
+    multi::fold,
     sequence::{delimited, preceded},
 };
 
@@ -45,18 +51,118 @@ pub fn keyword<'a>(
     delimited(multispace1, tag(ident), multispace1)
 }
 
-pub fn float(s: Span) -> ParserResult<f32> {
-    todo!()
+pub fn float<'a>(s: Span<'a>) -> ParserResult<'a, f32> {
+    digit1
+        .map_res(|s: Span<'a>| str::parse::<f32>(s.fragment()))
+        .parse(s)
 }
 
-pub fn string(s: Span) -> ParserResult<String> {
+pub fn identifier(s: Span) -> ParserResult<String> {
     todo!()
 }
 
-pub fn identifier(s: Span) -> ParserResult<String> {
-    todo!()
+pub fn number<'a>(s: Span<'a>) -> ParserResult<'a, i32> {
+    digit1
+        .map_res(|s: Span<'a>| str::parse::<i32>(s.fragment()))
+        .parse(s)
 }
 
-pub fn number(s: Span) -> ParserResult<i32> {
-   todo!() 
+pub fn string(span: Span) -> ParserResult<String> {
+    #[derive(Clone, Copy)]
+    enum StringFragment<'a> {
+        Literal(&'a str),
+        EscapedChar(char),
+        EscapedWhiteSpaces,
+    }
+
+    #[derive(Clone, Copy)]
+    enum StringDelimiterQuote {
+        Single,
+        Double,
+        TripleSingle,
+        TripleDouble,
+    }
+
+    impl StringDelimiterQuote {
+        fn as_str(&self) -> &'static str {
+            match self {
+                StringDelimiterQuote::Double => "\"",
+                StringDelimiterQuote::Single => "'",
+                StringDelimiterQuote::TripleSingle => "'''",
+                StringDelimiterQuote::TripleDouble => "\"\"\"",
+            }
+        }
+
+        fn get_parser<'a>(self) -> impl Parser<Span<'a>, Output = Self, Error = ParserError> {
+            value(self, tag(self.as_str()))
+        }
+    }
+
+    let span = multispace0(span)?.0;
+    let delimiter = peek(alt((
+        StringDelimiterQuote::Double.get_parser(),
+        StringDelimiterQuote::Single.get_parser(),
+        StringDelimiterQuote::TripleSingle.get_parser(),
+        StringDelimiterQuote::TripleDouble.get_parser(),
+    )))
+    .parse(span)?
+    .1;
+
+    // Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
+    let parse_unicode = delimited(
+        tag("u{"),
+        take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()),
+        char('}'),
+    )
+    .map(Span::into_fragment)
+    .map_res(move |hex: &str| u32::from_str_radix(hex, 16))
+    .map_opt(std::char::from_u32);
+
+    let parse_escaped_char = preceded(
+        char('\\'),
+        alt((
+            parse_unicode,
+            // The `value` parser returns a fixed value (the first argument) if it parser (the
+            // second argument) succeeds.
+            value('\n', char('n')),
+            value('\r', char('r')),
+            value('\t', char('t')),
+            value('\u{08}', char('b')),
+            value('\u{0C}', char('f')),
+            value('\\', char('\\')),
+            value('/', char('/')),
+            value('"', char('"')),
+            value('\'', char('\'')),
+        )),
+    );
+
+    let parse_fragment = alt((
+        // Take until the end of the string
+        verify(take_until(delimiter.as_str()), |s: &Span| !s.is_empty())
+            .map(Span::into_fragment)
+            .map(StringFragment::Literal),
+        // Be aware of escaped characters
+        parse_escaped_char.map(StringFragment::EscapedChar),
+        // We handle escaped whitespaces
+        value(
+            StringFragment::EscapedWhiteSpaces,
+            preceded(char('\\'), multispace1),
+        ),
+    ));
+
+    let from_fragments = |mut string: String, fragment| {
+        match fragment {
+            StringFragment::Literal(s) => string.push_str(s),
+            StringFragment::EscapedChar(c) => string.push(c),
+            StringFragment::EscapedWhiteSpaces => {}
+        }
+        string
+    };
+
+    delimited(
+        tag(delimiter.as_str()),
+        fold(0.., parse_fragment, String::default, from_fragments),
+        tag(delimiter.as_str()),
+    )
+    .parse(span)
 }