ADD: integers.
parent
690122ea4a
commit
bae09ec2f3
|
@ -1,6 +1,7 @@
|
||||||
MODULE ::= EXPR*
|
MODULE ::= EXPR*
|
||||||
EXPR ::=
|
EXPR ::=
|
||||||
bool
|
bool
|
||||||
|
| int
|
||||||
| ident
|
| ident
|
||||||
| VARDECL
|
| VARDECL
|
||||||
| FUNCALL
|
| FUNCALL
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
(assert-eq? 7 7)
|
||||||
|
|
||||||
|
(assert-eq? 0 (+))
|
||||||
|
(assert-eq? 3 (+ 3))
|
||||||
|
(assert-eq? 5 (+ 2 3))
|
||||||
|
|
||||||
|
(assert-eq? 0 (-))
|
||||||
|
(assert-eq? -3 (- 3))
|
||||||
|
(assert-eq? -1 (- 2 3))
|
||||||
|
(assert-eq? 5 (- 8 3))
|
||||||
|
|
||||||
|
(assert-eq? 1 (*))
|
||||||
|
(assert-eq? 6 (* 3 2))
|
||||||
|
(assert-eq? 120 (* 1 2 3 4 5))
|
||||||
|
|
||||||
|
(assert-eq? 1 (/))
|
||||||
|
(assert-eq? 6 (/ 6))
|
||||||
|
(assert-eq? 3 (/ 6 2))
|
||||||
|
(assert-eq? 2 (/ 12 2 3))
|
||||||
|
|
||||||
|
(assert-eq? 1 (%))
|
||||||
|
(assert-eq? 3 (% 7 4))
|
||||||
|
(assert-eq? 2 (% 13 7 4))
|
||||||
|
|
||||||
|
(assert-eq? 1 (^))
|
||||||
|
(assert-eq? 2 (^ 2))
|
||||||
|
(assert-eq? 8 (^ 2 3))
|
||||||
|
(assert-eq? 64 (^ 2 3 2))
|
152
lib/core.cpp
152
lib/core.cpp
|
@ -3,9 +3,156 @@
|
||||||
|
|
||||||
GRINO_ERROR(assertion_error);
|
GRINO_ERROR(assertion_error);
|
||||||
|
|
||||||
|
extern "C" void lib_int(grino::Loader& loader)
|
||||||
|
{
|
||||||
|
loader.add_native("+", [](auto args){
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (auto value: args)
|
||||||
|
{
|
||||||
|
result += value->as_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("*", [](auto args){
|
||||||
|
int result = 1;
|
||||||
|
|
||||||
|
for (auto value: args)
|
||||||
|
{
|
||||||
|
result *= value->as_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("-", [](auto args){
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = args[0]->as_int();
|
||||||
|
|
||||||
|
if (args.size() == 1)
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, -result);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=1; i<args.size(); i++)
|
||||||
|
{
|
||||||
|
result -= args[i]->as_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("/", [](auto args){
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = args[0]->as_int();
|
||||||
|
|
||||||
|
if (args.size() == 1)
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=1; i<args.size(); i++)
|
||||||
|
{
|
||||||
|
result /= args[i]->as_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("%", [](auto args){
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = args[0]->as_int();
|
||||||
|
|
||||||
|
if (args.size() == 1)
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=1; i<args.size(); i++)
|
||||||
|
{
|
||||||
|
result %= args[i]->as_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("^", [](auto args){
|
||||||
|
grino::Loc loc {"???", 0};
|
||||||
|
|
||||||
|
if (args.empty() == false)
|
||||||
|
{
|
||||||
|
loc = args.front()->loc();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return grino::Value::make_int(loc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = args[0]->as_int();
|
||||||
|
|
||||||
|
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_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void lib_assert(grino::Loader& loader)
|
extern "C" void lib_assert(grino::Loader& loader)
|
||||||
{
|
{
|
||||||
loader.add_native("assert", [](auto args){
|
loader.add_native("assert", [](auto args){
|
||||||
|
|
||||||
for (auto value: args)
|
for (auto value: args)
|
||||||
{
|
{
|
||||||
|
@ -21,7 +168,7 @@ extern "C" void lib_assert(grino::Loader& loader)
|
||||||
return grino::Value::make_bool(args.front()->loc(), true);
|
return grino::Value::make_bool(args.front()->loc(), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
loader.add_native("assert-eq?", [](auto args){
|
loader.add_native("assert-eq?", [](auto args){
|
||||||
auto lhs = args.front();
|
auto lhs = args.front();
|
||||||
|
|
||||||
for (size_t i=1; i<args.size(); i++)
|
for (size_t i=1; i<args.size(); i++)
|
||||||
|
@ -50,6 +197,7 @@ extern "C" void lib_assert(grino::Loader& loader)
|
||||||
extern "C" void lib(grino::Loader& loader)
|
extern "C" void lib(grino::Loader& loader)
|
||||||
{
|
{
|
||||||
lib_assert(loader);
|
lib_assert(loader);
|
||||||
|
lib_int(loader);
|
||||||
|
|
||||||
loader.add_native("dump", [](auto args){
|
loader.add_native("dump", [](auto args){
|
||||||
std::string sep;
|
std::string sep;
|
||||||
|
|
|
@ -46,6 +46,14 @@ namespace grino
|
||||||
program.push_constant(value));
|
program.push_constant(value));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_INT: {
|
||||||
|
std::string repr = node->repr();
|
||||||
|
auto value = Value::make_int(node->loc(), std::stoi(repr));
|
||||||
|
|
||||||
|
program.push_instr(OPCODE_LOAD_CONST,
|
||||||
|
program.push_constant(value));
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_VARDECL: {
|
case NODE_VARDECL: {
|
||||||
std::string ident = node->child(0).lock()->repr();
|
std::string ident = node->child(0).lock()->repr();
|
||||||
auto expr = node->child(1).lock();
|
auto expr = node->child(1).lock();
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace grino
|
||||||
add_keyword(NODE_BOOL, "true", true);
|
add_keyword(NODE_BOOL, "true", true);
|
||||||
add_keyword(NODE_BOOL, "false", true);
|
add_keyword(NODE_BOOL, "false", true);
|
||||||
|
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,4 +223,35 @@ namespace grino
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> Lexer::scan_int()
|
||||||
|
{
|
||||||
|
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 (repr.empty()
|
||||||
|
|| repr.back() == '-')
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ScanInfo {
|
||||||
|
cursor,
|
||||||
|
NODE_INT,
|
||||||
|
repr
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace grino
|
||||||
bool has_value);
|
bool has_value);
|
||||||
|
|
||||||
std::optional<ScanInfo> scan_ident();
|
std::optional<ScanInfo> scan_ident();
|
||||||
|
std::optional<ScanInfo> scan_int();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_MODULE), \
|
G(NODE_MODULE), \
|
||||||
G(NODE_BOOL), \
|
G(NODE_BOOL), \
|
||||||
|
G(NODE_INT), \
|
||||||
G(NODE_VARDECL), \
|
G(NODE_VARDECL), \
|
||||||
G(NODE_FUNCALL), \
|
G(NODE_FUNCALL), \
|
||||||
G(NODE_IDENT), \
|
G(NODE_IDENT), \
|
||||||
|
|
|
@ -128,7 +128,8 @@ namespace grino
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_is(NODE_IDENT)
|
if (type_is(NODE_IDENT)
|
||||||
|| type_is(NODE_BOOL))
|
|| type_is(NODE_BOOL)
|
||||||
|
|| type_is(NODE_INT))
|
||||||
{
|
{
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,14 @@ namespace grino
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*static*/ std::shared_ptr<Value> Value::make_int(Loc const& loc, int val)
|
||||||
|
{
|
||||||
|
auto value = std::make_shared<Value>(loc);
|
||||||
|
value->m_type = TYPE_INT;
|
||||||
|
value->m_int_val = val;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
std::shared_ptr<Value> Value::make_native_function(Loc const& loc,
|
std::shared_ptr<Value> Value::make_native_function(Loc const& loc,
|
||||||
native_t val)
|
native_t val)
|
||||||
|
@ -40,6 +48,7 @@ namespace grino
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case TYPE_NIL: return "<nil>";
|
case TYPE_NIL: return "<nil>";
|
||||||
|
case TYPE_INT: return std::to_string(*m_int_val);
|
||||||
case TYPE_BOOL: return *m_bool_val ? "true" : "false";
|
case TYPE_BOOL: return *m_bool_val ? "true" : "false";
|
||||||
case TYPE_FUNCTION: return "<function>";
|
case TYPE_FUNCTION: return "<function>";
|
||||||
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
|
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
|
||||||
|
@ -58,6 +67,7 @@ namespace grino
|
||||||
{
|
{
|
||||||
case TYPE_NIL: return true;
|
case TYPE_NIL: return true;
|
||||||
case TYPE_BOOL: return *m_bool_val == *other.m_bool_val;
|
case TYPE_BOOL: return *m_bool_val == *other.m_bool_val;
|
||||||
|
case TYPE_INT: return *m_int_val == *other.m_int_val;
|
||||||
case TYPE_REF: return *m_ref_val == *other.m_ref_val;
|
case TYPE_REF: return *m_ref_val == *other.m_ref_val;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace grino
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Value> make_nil(Loc const& loc);
|
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_bool(Loc const& loc, bool val);
|
||||||
|
static std::shared_ptr<Value> make_int(Loc const& loc, int val);
|
||||||
static std::shared_ptr<Value> make_native_function(Loc const& loc,
|
static std::shared_ptr<Value> make_native_function(Loc const& loc,
|
||||||
native_t val);
|
native_t val);
|
||||||
static std::shared_ptr<Value> make_ref(Loc const& loc,
|
static std::shared_ptr<Value> make_ref(Loc const& loc,
|
||||||
|
@ -24,6 +25,7 @@ namespace grino
|
||||||
Loc loc() const { return m_loc; }
|
Loc loc() const { return m_loc; }
|
||||||
TypeType type() const { return m_type; }
|
TypeType type() const { return m_type; }
|
||||||
bool as_bool() const { return *m_bool_val; }
|
bool as_bool() const { return *m_bool_val; }
|
||||||
|
int as_int() const { return *m_int_val; }
|
||||||
std::shared_ptr<Function> as_function() const { return m_function_val; }
|
std::shared_ptr<Function> as_function() const { return m_function_val; }
|
||||||
size_t as_ref() const { return *m_ref_val; }
|
size_t as_ref() const { return *m_ref_val; }
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@ namespace grino
|
||||||
Loc m_loc;
|
Loc m_loc;
|
||||||
TypeType m_type = TYPE_NIL;
|
TypeType m_type = TYPE_NIL;
|
||||||
std::optional<bool> m_bool_val;
|
std::optional<bool> m_bool_val;
|
||||||
|
std::optional<int> m_int_val;
|
||||||
std::shared_ptr<Function> m_function_val;
|
std::shared_ptr<Function> m_function_val;
|
||||||
std::optional<size_t> m_ref_val;
|
std::optional<size_t> m_ref_val;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define grino_COMMONS_HPP
|
#define grino_COMMONS_HPP
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define TYPES(G) \
|
#define TYPES(G) \
|
||||||
G(TYPE_NIL), \
|
G(TYPE_NIL), \
|
||||||
G(TYPE_BOOL), \
|
G(TYPE_BOOL), \
|
||||||
|
G(TYPE_INT), \
|
||||||
G(TYPE_FUNCTION), \
|
G(TYPE_FUNCTION), \
|
||||||
G(TYPE_REF)
|
G(TYPE_REF)
|
||||||
|
|
||||||
|
|
|
@ -77,3 +77,16 @@ TEST_CASE_METHOD(LexerTest, "Lexer_no_end_space")
|
||||||
test_next(lexer, "CPAR");
|
test_next(lexer, "CPAR");
|
||||||
test_end(lexer);
|
test_end(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_int")
|
||||||
|
{
|
||||||
|
grino::Lexer lexer {m_logger, "tests/lexer"};
|
||||||
|
|
||||||
|
lexer.scan("4 39 256 2 -7");
|
||||||
|
test_next(lexer, "INT[4]");
|
||||||
|
test_next(lexer, "INT[39]");
|
||||||
|
test_next(lexer, "INT[256]");
|
||||||
|
test_next(lexer, "INT[2]");
|
||||||
|
test_next(lexer, "INT[-7]");
|
||||||
|
test_end(lexer);
|
||||||
|
}
|
||||||
|
|
|
@ -48,3 +48,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_funcall")
|
||||||
test_parse("MODULE(FUNCALL(IDENT[f],BOOL[false],BOOL[true]))",
|
test_parse("MODULE(FUNCALL(IDENT[f],BOOL[false],BOOL[true]))",
|
||||||
"(f false true)");
|
"(f false true)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_integer")
|
||||||
|
{
|
||||||
|
test_parse("MODULE(FUNCALL(IDENT[hello],INT[2],INT[34]))",
|
||||||
|
"(hello 2 34)");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue