ADD: strings.

main
bog 2023-09-13 13:45:09 +02:00
parent f2c9a6248a
commit 25bd1f28f6
13 changed files with 170 additions and 15 deletions

View File

@ -4,6 +4,7 @@ EXPR ::=
| int
| ident
| float
| string
| VARDECL
| FUNDECL
| FUNCALL

11
examples/string.gri Normal file
View File

@ -0,0 +1,11 @@
(assert= 'hello' 'hello')
(assert (not (eq? 'bim' 'bam')))
(assert= false (empty? 'coucou'))
(assert= true (empty? ''))
(assert= 'e' (ref 'hello' 1))
(assert= 5 (len 'hello'))
(assert= 'aaa' (dup 'a' 3))
(assert= 'abcdefg' (cat 'abc' 'def' 'g'))

View File

@ -5,7 +5,7 @@
GRINO_ERROR(assertion_error);
extern "C" void lib_array(grino::Loader& loader)
extern "C" void lib_collection(grino::Loader& loader)
{
loader.add_native("ref", [&loader](auto args){
std::vector<size_t> idxs;
@ -14,6 +14,12 @@ extern "C" void lib_array(grino::Loader& loader)
idxs.push_back(args[i]->as_int());
}
if (args[0]->type() == grino::TYPE_STRING)
{
auto char_val = std::string(1, args[0]->as_string()[args[1]->as_int()]);
return grino::Value::make_string(args[0]->loc(), char_val);
}
std::function<std::shared_ptr<grino::Value>
(std::shared_ptr<grino::Value>, std::vector<size_t>)>
f = [&](std::shared_ptr<grino::Value> val, std::vector<size_t> indexes){
@ -37,14 +43,38 @@ extern "C" void lib_array(grino::Loader& loader)
});
loader.add_native("empty?", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto val = args[0];
if (val->type() == grino::TYPE_STRING)
{
std::string str = val->as_string();
return grino::Value::make_bool(val->loc(), str.empty());
}
size_t ref = val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return grino::Value::make_bool(array_val->loc(), array.empty());
});
loader.add_native("len", [&loader](auto args){
auto val = args[0];
if (val->type() == grino::TYPE_STRING)
{
return grino::Value::make_int(val->loc(), val->as_string().size());
}
size_t ref = val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return grino::Value::make_int(array_val->loc(), array.size());
});
}
extern "C" void lib_array(grino::Loader& loader)
{
loader.add_native("head", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
@ -87,15 +117,6 @@ extern "C" void lib_array(grino::Loader& loader)
return grino::Value::make_ref(array_val->loc(), addr);
});
loader.add_native("len", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return grino::Value::make_int(array_val->loc(), array.size());
});
}
extern "C" void lib_flow_control(grino::Loader& loader)
@ -611,6 +632,33 @@ extern "C" void lib_assert(grino::Loader& loader)
});
}
extern "C" void lib_string(grino::Loader& loader)
{
loader.add_native("dup", [](auto args) {
std::string value = args[0]->as_string();
size_t count = args[1]->as_int();
std::string result;
for (size_t i=0; i<count; i++)
{
result += value;
}
return grino::Value::make_string(args[0]->loc(), result);
});
loader.add_native("cat", [](auto args) {
std::string result;
for (auto arg: args)
{
result += arg->as_string();
}
return grino::Value::make_string(args[0]->loc(), result);
});
}
extern "C" void lib(grino::Loader& loader)
{
lib_assert(loader);
@ -619,7 +667,9 @@ extern "C" void lib(grino::Loader& loader)
lib_cmp(loader);
lib_bool(loader);
lib_flow_control(loader);
lib_collection(loader);
lib_array(loader);
lib_string(loader);
loader.add_native("dump", [](auto args){
std::string sep;

View File

@ -154,6 +154,16 @@ namespace grino
program.push_constant(value));
} break;
case NODE_STRING: {
std::string repr = node->repr();
std::string val = repr.substr(1, repr.size() - 2);
auto value = Value::make_string(node->loc(), val);
program.push_instr(OPCODE_LOAD_CONST,
program.push_constant(value));
} break;
case NODE_VARDECL: {
std::string ident = node->child(0).lock()->repr();
auto expr = node->child(1).lock();

View File

@ -20,6 +20,7 @@ namespace grino
m_scanners.push_back(std::bind(&Lexer::scan_float, this));
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
m_scanners.push_back(std::bind(&Lexer::scan_string, this));
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
}
@ -150,6 +151,50 @@ namespace grino
text, has_value));
}
std::optional<ScanInfo> Lexer::scan_string()
{
size_t cursor = m_cursor;
std::string repr = "'";
auto has_delim = [&](size_t idx){
if (idx >= m_source.size()) { return false; }
bool is_escaped = idx > 0 && m_source[idx - 1] == '\\';
return m_source[idx] == '\'' && !is_escaped;
};
if (!has_delim(cursor))
{
return std::nullopt;
}
cursor++;
while (has_more(cursor)
&& !has_delim(cursor))
{
if (at(cursor) != '\\')
{
repr += at(cursor);
}
cursor++;
}
if (has_delim(cursor))
{
repr += "'";
cursor++;
return ScanInfo {
cursor,
NODE_STRING,
repr
};
}
return std::nullopt;
}
std::optional<ScanInfo> Lexer::scan_text(NodeType type,
std::string const& text,
bool has_value)

View File

@ -49,6 +49,7 @@ namespace grino
std::string const& text,
bool has_value = false);
std::optional<ScanInfo> scan_string();
std::optional<ScanInfo> scan_text(NodeType type,
std::string const& text,
bool has_value);

View File

@ -22,7 +22,8 @@
G(NODE_CSQUARE), \
G(NODE_BLOCK), \
G(NODE_ARRAY), \
G(NODE_FLOAT)
G(NODE_FLOAT), \
G(NODE_STRING)
namespace grino
{

View File

@ -151,7 +151,8 @@ namespace grino
if (type_is(NODE_IDENT)
|| type_is(NODE_BOOL)
|| type_is(NODE_INT)
|| type_is(NODE_FLOAT))
|| type_is(NODE_FLOAT)
|| type_is(NODE_STRING))
{
return consume();
}

View File

@ -1,5 +1,6 @@
#include "Value.hpp"
#include "Program.hpp"
#include "src/types.hpp"
namespace grino
{
@ -104,6 +105,16 @@ namespace grino
return value;
}
/*static*/
std::shared_ptr<Value> Value::make_string(Loc const& loc,
std::string const& val)
{
auto value = std::make_shared<Value>(loc);
value->m_type = TYPE_STRING;
value->m_string_val = val;
return value;
}
std::shared_ptr<Program> Value::as_program() const
{
return m_program_val;
@ -114,6 +125,7 @@ namespace grino
switch (m_type)
{
case TYPE_NIL: return "<nil>";
case TYPE_STRING: return *m_string_val;
case TYPE_INT: return std::to_string(*m_int_val);
case TYPE_FLOAT: return std::to_string(*m_float_val);
case TYPE_BOOL: return *m_bool_val ? "true" : "false";
@ -149,6 +161,7 @@ namespace grino
case TYPE_NIL: return true;
case TYPE_BOOL: return *m_bool_val == *other.m_bool_val;
case TYPE_INT: return *m_int_val == *other.m_int_val;
case TYPE_STRING: return *m_string_val == *other.m_string_val;
case TYPE_FLOAT:
return std::fabs(*m_float_val - *other.m_float_val) < FLOAT_APPROX;
case TYPE_REF: return *m_ref_val == *other.m_ref_val;

View File

@ -37,6 +37,9 @@ namespace grino
static std::shared_ptr<Value> make_array(Loc const& loc,
val_array_t val);
static std::shared_ptr<Value> make_string(Loc const& loc,
std::string const& val);
explicit Value(Loc const& loc);
virtual ~Value() = default;
@ -50,6 +53,7 @@ namespace grino
std::shared_ptr<Program> as_program() const;
val_array_t& as_array() { return *m_array_val; }
val_array_t const& as_array() const { return *m_array_val; }
std::string const& as_string() const { return *m_string_val; }
std::string string() const;
bool equals(Value const& other) const;
@ -64,6 +68,7 @@ namespace grino
std::shared_ptr<Program> m_program_val;
std::optional<size_t> m_ref_val;
std::optional<val_array_t> m_array_val;
std::optional<std::string> m_string_val;
};
}

View File

@ -11,7 +11,8 @@
G(TYPE_REF), \
G(TYPE_PROGRAM), \
G(TYPE_FLOAT), \
G(TYPE_ARRAY)
G(TYPE_ARRAY), \
G(TYPE_STRING)
namespace grino

View File

@ -119,3 +119,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_float")
test_next(lexer, "FLOAT[1.0]");
test_end(lexer);
}
TEST_CASE_METHOD(LexerTest, "Lexer_strings")
{
grino::Lexer lexer {m_logger, "tests/lexer"};
lexer.scan(" ' hello ' '\\'bim\\'' ");
test_next(lexer, "STRING[' hello ']");
test_next(lexer, "STRING[''bim'']");
test_end(lexer);
}

View File

@ -99,3 +99,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_float")
test_parse("MODULE(BLOCK(ARRAY(INT[1],FLOAT[28.5],IDENT[salut])))",
"(: [1 28.5 salut] )");
}
TEST_CASE_METHOD(ParserTest, "Parser_string")
{
test_parse("MODULE(BLOCK(ARRAY(STRING['bim !'],FLOAT[28.5],IDENT[salut])))",
"(: ['bim !' 28.5 salut] )");
}