ADD: floats.
parent
8fa9957575
commit
f2c9a6248a
|
@ -3,6 +3,7 @@ EXPR ::=
|
|||
bool
|
||||
| int
|
||||
| ident
|
||||
| float
|
||||
| VARDECL
|
||||
| FUNDECL
|
||||
| FUNCALL
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
(assert= 3.2 3.2)
|
||||
(assert= false (eq? 3.7 7.2))
|
||||
(assert= true (ne? 3.7 7.2))
|
||||
|
||||
(assert= 3.1 (+. 1.0 2.1))
|
||||
(assert= -1.1 (-. 1.0 2.1))
|
||||
(assert= 7.8 (*. 5.2 1.5))
|
||||
(assert= 2.5 (/. 5.0 2.0))
|
||||
(assert= 1.25 (%. 10.0 1.75))
|
||||
(assert= 8.0 (^. 2.0 3.0))
|
||||
|
||||
(assert= true (< 1.0 2.0))
|
||||
(assert= false (< 2.0 2.0))
|
||||
(assert= false (< 3.0 2.0))
|
||||
|
||||
(assert= true (<= 1.0 2.0))
|
||||
(assert= true (<= 2.0 2.0))
|
||||
(assert= false (<= 3.0 2.0))
|
||||
|
||||
(assert= true (> 18.0 5.3))
|
||||
(assert= false (> 18.0 18.0))
|
||||
(assert= false (> 18.0 115.3))
|
||||
|
||||
(assert= true (>= 18.0 5.3))
|
||||
(assert= true (>= 18.0 18.0))
|
||||
(assert= false (>= 18.0 115.3))
|
202
lib/core.cpp
202
lib/core.cpp
|
@ -267,41 +267,236 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
});
|
||||
}
|
||||
|
||||
extern "C" void lib_float(grino::Loader& loader)
|
||||
{
|
||||
loader.add_native("+.", [](auto args){
|
||||
float result = 0;
|
||||
|
||||
for (auto value: args)
|
||||
{
|
||||
result += value->as_float();
|
||||
}
|
||||
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
|
||||
loader.add_native("*.", [](auto args){
|
||||
float result = 1;
|
||||
|
||||
for (auto value: args)
|
||||
{
|
||||
result *= value->as_float();
|
||||
}
|
||||
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
|
||||
loader.add_native("-.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
else
|
||||
{
|
||||
return grino::Value::make_float(loc, 0);
|
||||
}
|
||||
|
||||
float result = args[0]->as_float();
|
||||
|
||||
if (args.size() == 1)
|
||||
{
|
||||
return grino::Value::make_float(loc, -result);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<args.size(); i++)
|
||||
{
|
||||
result -= args[i]->as_float();
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
|
||||
loader.add_native("/.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
else
|
||||
{
|
||||
return grino::Value::make_float(loc, 1.0f);
|
||||
}
|
||||
|
||||
float result = args[0]->as_float();
|
||||
|
||||
if (args.size() == 1)
|
||||
{
|
||||
return grino::Value::make_float(loc, result);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<args.size(); i++)
|
||||
{
|
||||
result /= args[i]->as_float();
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
|
||||
loader.add_native("%.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
else
|
||||
{
|
||||
return grino::Value::make_float(loc, 1);
|
||||
}
|
||||
|
||||
float result = args[0]->as_float();
|
||||
|
||||
if (args.size() == 1)
|
||||
{
|
||||
return grino::Value::make_float(loc, result);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<args.size(); i++)
|
||||
{
|
||||
result = std::fmod(result, args[i]->as_float());
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
|
||||
loader.add_native("^.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
loc = args.front()->loc();
|
||||
}
|
||||
else
|
||||
{
|
||||
return grino::Value::make_float(loc, 1);
|
||||
}
|
||||
|
||||
float result = args[0]->as_float();
|
||||
|
||||
if (args.size() == 1)
|
||||
{
|
||||
return grino::Value::make_int(loc, result);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<args.size(); i++)
|
||||
{
|
||||
result = std::pow(result, args[i]->as_float());
|
||||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void lib_cmp(grino::Loader& loader)
|
||||
{
|
||||
loader.add_native("<", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
{
|
||||
int lhs = args[0]->as_int();
|
||||
int rhs = args[1]->as_int();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs < rhs);
|
||||
}
|
||||
else if (args[0]->type() == grino::TYPE_FLOAT)
|
||||
{
|
||||
float lhs = args[0]->as_float();
|
||||
float rhs = args[1]->as_float();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs < rhs);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
|
||||
loader.add_native("<=", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
{
|
||||
int lhs = args[0]->as_int();
|
||||
int rhs = args[1]->as_int();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs <= rhs);
|
||||
}
|
||||
else if (args[0]->type() == grino::TYPE_FLOAT)
|
||||
{
|
||||
float lhs = args[0]->as_float();
|
||||
float rhs = args[1]->as_float();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs <= rhs);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
|
||||
loader.add_native(">", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
{
|
||||
int lhs = args[0]->as_int();
|
||||
int rhs = args[1]->as_int();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs > rhs);
|
||||
}
|
||||
else if (args[0]->type() == grino::TYPE_FLOAT)
|
||||
{
|
||||
float lhs = args[0]->as_float();
|
||||
float rhs = args[1]->as_float();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs > rhs);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
|
||||
loader.add_native(">=", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
{
|
||||
int lhs = args[0]->as_int();
|
||||
int rhs = args[1]->as_int();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs >= rhs);
|
||||
}
|
||||
else if (args[0]->type() == grino::TYPE_FLOAT)
|
||||
{
|
||||
float lhs = args[0]->as_float();
|
||||
float rhs = args[1]->as_float();
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs >= rhs);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
|
||||
loader.add_native("ne?", [](auto args){
|
||||
int lhs = args[0]->as_int();
|
||||
int rhs = args[1]->as_int();
|
||||
auto lhs = args[0];
|
||||
auto rhs = args[1];
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), lhs != rhs);
|
||||
return grino::Value::make_bool(args[0]->loc(), !lhs->equals(*rhs));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -420,6 +615,7 @@ extern "C" void lib(grino::Loader& loader)
|
|||
{
|
||||
lib_assert(loader);
|
||||
lib_int(loader);
|
||||
lib_float(loader);
|
||||
lib_cmp(loader);
|
||||
lib_bool(loader);
|
||||
lib_flow_control(loader);
|
||||
|
|
|
@ -145,6 +145,15 @@ namespace grino
|
|||
program.push_constant(value));
|
||||
} break;
|
||||
|
||||
case NODE_FLOAT: {
|
||||
std::string repr = node->repr();
|
||||
|
||||
auto value = Value::make_float(node->loc(), std::stof(repr));
|
||||
|
||||
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();
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace grino
|
|||
add_keyword(NODE_BOOL, "true", true);
|
||||
add_keyword(NODE_BOOL, "false", true);
|
||||
|
||||
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_ident, this));
|
||||
}
|
||||
|
@ -258,4 +259,51 @@ namespace grino
|
|||
repr
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<ScanInfo> Lexer::scan_float()
|
||||
{
|
||||
size_t cursor = m_cursor;
|
||||
std::string repr;
|
||||
|
||||
if (has_more(cursor) && at(cursor) == '-')
|
||||
{
|
||||
repr += "-";
|
||||
cursor++;
|
||||
}
|
||||
|
||||
while (has_more(cursor)
|
||||
&& std::isdigit(at(cursor)))
|
||||
{
|
||||
repr += at(cursor);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (!has_more(cursor) || at(cursor) != '.')
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
repr += at(cursor);
|
||||
cursor++;
|
||||
|
||||
while (has_more(cursor)
|
||||
&& std::isdigit(at(cursor)))
|
||||
{
|
||||
repr += at(cursor);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (repr.empty()
|
||||
|| repr.back() == '-'
|
||||
|| repr.back() == '.')
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return ScanInfo {
|
||||
cursor,
|
||||
NODE_FLOAT,
|
||||
repr
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace grino
|
|||
bool has_value);
|
||||
|
||||
std::optional<ScanInfo> scan_ident();
|
||||
std::optional<ScanInfo> scan_float();
|
||||
std::optional<ScanInfo> scan_int();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
G(NODE_OSQUARE), \
|
||||
G(NODE_CSQUARE), \
|
||||
G(NODE_BLOCK), \
|
||||
G(NODE_ARRAY)
|
||||
G(NODE_ARRAY), \
|
||||
G(NODE_FLOAT)
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
|
|
@ -150,7 +150,8 @@ namespace grino
|
|||
|
||||
if (type_is(NODE_IDENT)
|
||||
|| type_is(NODE_BOOL)
|
||||
|| type_is(NODE_INT))
|
||||
|| type_is(NODE_INT)
|
||||
|| type_is(NODE_FLOAT))
|
||||
{
|
||||
return consume();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@ namespace grino
|
|||
return value;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<Value> Value::make_float(Loc const& loc, float val)
|
||||
{
|
||||
auto value = std::make_shared<Value>(loc);
|
||||
value->m_type = TYPE_FLOAT;
|
||||
value->m_float_val = val;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
std::shared_ptr<Value> Value::make_native_function(Loc const& loc,
|
||||
native_t val)
|
||||
|
@ -107,6 +115,7 @@ namespace grino
|
|||
{
|
||||
case TYPE_NIL: return "<nil>";
|
||||
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";
|
||||
case TYPE_FUNCTION: return "<function>";
|
||||
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
|
||||
|
@ -140,6 +149,8 @@ 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_FLOAT:
|
||||
return std::fabs(*m_float_val - *other.m_float_val) < FLOAT_APPROX;
|
||||
case TYPE_REF: return *m_ref_val == *other.m_ref_val;
|
||||
case TYPE_PROGRAM: return false;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace grino
|
|||
static std::shared_ptr<Value> make_nil(Loc const& loc);
|
||||
static std::shared_ptr<Value> make_bool(Loc const& loc, bool val);
|
||||
static std::shared_ptr<Value> make_int(Loc const& loc, int val);
|
||||
static std::shared_ptr<Value> make_float(Loc const& loc, float val);
|
||||
static std::shared_ptr<Value> make_native_function(Loc const& loc,
|
||||
native_t val);
|
||||
static std::shared_ptr<Value> make_function(Loc const& loc,
|
||||
|
@ -42,6 +43,7 @@ namespace grino
|
|||
Loc loc() const { return m_loc; }
|
||||
TypeType type() const { return m_type; }
|
||||
bool as_bool() const { return *m_bool_val; }
|
||||
float as_float() const { return *m_float_val; }
|
||||
int as_int() const { return *m_int_val; }
|
||||
std::shared_ptr<Function> as_function() const { return m_function_val; }
|
||||
size_t as_ref() const { return *m_ref_val; }
|
||||
|
@ -57,6 +59,7 @@ namespace grino
|
|||
TypeType m_type = TYPE_NIL;
|
||||
std::optional<bool> m_bool_val;
|
||||
std::optional<int> m_int_val;
|
||||
std::optional<float> m_float_val;
|
||||
std::shared_ptr<Function> m_function_val;
|
||||
std::shared_ptr<Program> m_program_val;
|
||||
std::optional<size_t> m_ref_val;
|
||||
|
|
|
@ -16,4 +16,6 @@
|
|||
#include "config.hpp"
|
||||
#include "mutils.hpp"
|
||||
|
||||
#define FLOAT_APPROX 0.001f
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
G(TYPE_FUNCTION), \
|
||||
G(TYPE_REF), \
|
||||
G(TYPE_PROGRAM), \
|
||||
G(TYPE_FLOAT), \
|
||||
G(TYPE_ARRAY)
|
||||
|
||||
|
||||
|
|
|
@ -109,12 +109,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_block")
|
|||
test_end(lexer);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_array")
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_float")
|
||||
{
|
||||
grino::Lexer lexer {m_logger, "tests/lexer"};
|
||||
|
||||
lexer.scan(" [] ");
|
||||
test_next(lexer, "OSQUARE");
|
||||
test_next(lexer, "CSQUARE");
|
||||
lexer.scan(" 3.12 -0.7 1.0");
|
||||
test_next(lexer, "FLOAT[3.12]");
|
||||
test_next(lexer, "FLOAT[-0.7]");
|
||||
test_next(lexer, "FLOAT[1.0]");
|
||||
test_end(lexer);
|
||||
}
|
||||
|
|
|
@ -93,3 +93,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_array")
|
|||
test_parse("MODULE(BLOCK(ARRAY(INT[1],BOOL[true],IDENT[salut])))",
|
||||
"(: [1 true salut] )");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_float")
|
||||
{
|
||||
test_parse("MODULE(BLOCK(ARRAY(INT[1],FLOAT[28.5],IDENT[salut])))",
|
||||
"(: [1 28.5 salut] )");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue