Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ratio #117

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler+runtime/bin/build-clang
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function build()
cd "${srcdir}/llvm-build"

cmake -DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_RUNTIMES=all \
-DLLVM_ENABLE_RUNTIMES=all \
-DCMAKE_CXX_STANDARD=20 \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
-DLLVM_TARGETS_TO_BUILD="host" \
Expand Down
21 changes: 20 additions & 1 deletion compiler+runtime/include/cpp/jank/read/lex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,23 @@ namespace jank::read::lex
integer,
/* Has double data. */
real,
/* Has two integer data. */
ratio,
/* Has string data. */
string,
/* Has string data. */
escaped_string,
eof,
};

struct ratio
{
native_integer numerator{};
native_integer denominator{};
native_bool operator==(ratio const &rhs) const;
native_bool operator!=(ratio const &rhs) const;
};

struct token
{
token() = default;
Expand All @@ -65,6 +75,7 @@ namespace jank::read::lex
token(size_t const p, size_t const s, token_kind const k, native_persistent_string_view const);
token(size_t const p, size_t const s, token_kind const k, char const * const);
token(size_t const p, size_t const s, token_kind const k, native_bool const);
token(size_t const p, size_t const s, token_kind const k, ratio const);

native_bool operator==(token const &rhs) const;
native_bool operator!=(token const &rhs) const;
Expand All @@ -81,12 +92,18 @@ namespace jank::read::lex
size_t pos{ ignore_pos };
size_t size{ 1 };
token_kind kind{ token_kind::eof };
boost::variant<no_data, native_integer, native_real, native_persistent_string_view, native_bool>
boost::variant<no_data,
native_integer,
native_real,
native_persistent_string_view,
native_bool,
ratio>
data;
};

std::ostream &operator<<(std::ostream &os, token const &t);
std::ostream &operator<<(std::ostream &os, token::no_data const &t);
std::ostream &operator<<(std::ostream &os, ratio const &t);
}

namespace jank::read
Expand Down Expand Up @@ -142,6 +159,8 @@ namespace jank::read::lex
size_t pos{};
/* Whether or not the previous token requires a space after it. */
native_bool require_space{};
/* True when seeing a '/' following a number. */
native_bool found_slash_after_number{};
native_persistent_string_view file;
};
}
1 change: 1 addition & 0 deletions compiler+runtime/include/cpp/jank/read/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ namespace jank::read::parse
object_result parse_boolean();
object_result parse_keyword();
object_result parse_integer();
object_result parse_ratio();
object_result parse_real();
object_result parse_string();
object_result parse_escaped_string();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace jank::runtime::behavior
{
template <typename T>
concept comparable = requires(T * const t) {
/* Returns how this object compares to the specified object. Comparison, unlike equality,
/* Returns how this object compares to the specified object. Comparison, unlike equality,
* can only be done for objects of the same type. If there's a type mismatch, this function
* is expected to throw. There are three cases to handle:
*
Expand All @@ -14,6 +14,6 @@ namespace jank::runtime::behavior
*
* For sequences, all values need to be considered for comparison.
*/
{ t->compare(std::declval<object const &>()) } -> std::convertible_to<native_integer>;
{ t->compare(std::declval<object const &>()) } -> std::convertible_to<native_integer>;
};
}
9 changes: 3 additions & 6 deletions compiler+runtime/src/cpp/jank/analyze/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,8 +837,7 @@ namespace jank::analyze
}

auto const condition(o->data.rest().first().unwrap());
auto condition_expr(
analyze(condition, current_frame, expression_type::nested, fn_ctx, false));
auto condition_expr(analyze(condition, current_frame, expression_type::nested, fn_ctx, false));
if(condition_expr.is_err())
{
return condition_expr.expect_err_move();
Expand Down Expand Up @@ -1402,8 +1401,7 @@ namespace jank::analyze
return found_special->second(o, current_frame, expr_type, fn_ctx, needs_box);
}

auto sym_result(
analyze_symbol(sym, current_frame, expression_type::nested, fn_ctx, true));
auto sym_result(analyze_symbol(sym, current_frame, expression_type::nested, fn_ctx, true));
if(sym_result.is_err())
{
return sym_result;
Expand Down Expand Up @@ -1466,8 +1464,7 @@ namespace jank::analyze
}
else
{
auto callable_expr(
analyze(first, current_frame, expression_type::nested, fn_ctx, needs_box));
auto callable_expr(analyze(first, current_frame, expression_type::nested, fn_ctx, needs_box));
if(callable_expr.is_err())
{
return callable_expr;
Expand Down
95 changes: 92 additions & 3 deletions compiler+runtime/src/cpp/jank/read/lex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,24 @@ namespace jank::read
{
}

token::token(size_t const p, size_t const s, token_kind const k, ratio const d)
: pos{ p }
, size{ s }
, kind{ k }
, data{ d }
{
}

native_bool ratio::operator==(ratio const &rhs) const
{
return numerator == rhs.numerator && denominator == rhs.denominator;
}

native_bool ratio::operator!=(ratio const &rhs) const
{
return !(*this == rhs);
}

native_bool token::no_data::operator==(no_data const &) const
{
return true;
Expand Down Expand Up @@ -186,6 +204,11 @@ namespace jank::read
return os << "<no data>";
}

std::ostream &operator<<(std::ostream &os, ratio const &r)
{
return os << r.numerator << "/" << r.denominator;
}

processor::processor(native_persistent_string_view const &f)
: file{ f }
{
Expand Down Expand Up @@ -366,6 +389,9 @@ namespace jank::read
}
native_bool contains_leading_digit{ file[token_start] != '-' };
native_bool contains_dot{};
native_bool is_scientific{};
native_bool found_exponent_sign{};
native_bool expecting_exponent{};
while(true)
{
auto const oc(peek());
Expand All @@ -377,30 +403,93 @@ namespace jank::read
auto const c(oc.unwrap());
if(c == '.')
{
if(contains_dot || !contains_leading_digit)
if(contains_dot || is_scientific || !contains_leading_digit)
{
++pos;
return err(error{ token_start, pos, "invalid number" });
}
contains_dot = true;
}
else if(c == 'e' || c == 'E')
{
if(is_scientific || !contains_leading_digit)
{
++pos;
return err(error{ token_start, pos, "invalid number" });
}
is_scientific = true;
expecting_exponent = true;
}
else if(c == '+' || c == '-')
{
if(found_exponent_sign || !is_scientific || !expecting_exponent)
{
++pos;
return err(error{ token_start, pos, "invalid number" });
}
found_exponent_sign = true;
}
else if(c == '/')
{
require_space = false;
++pos;
if(found_exponent_sign || is_scientific || expecting_exponent || contains_dot
|| found_slash_after_number)
{
return err(error{ token_start, pos, "invalid ratio" });
}
found_slash_after_number = true;
/* skip the '/' char and look for the denominator number. */
++pos;
auto const denominator(next());
if(denominator.is_ok() && denominator.expect_ok().kind == token_kind::integer)
{
auto const &denominator_token(denominator.expect_ok());
found_slash_after_number = false;
return ok(
token(token_start,
pos - token_start,
token_kind::ratio,
{ .numerator = std::strtoll(file.data() + token_start, nullptr, 10),
.denominator = boost::get<native_integer>(denominator_token.data) }));
}
return err(
error{ token_start, pos, "invalid ratio: expecting an integer denominator" });
}
else if(std::isdigit(c) == 0)
{
if(expecting_exponent)
{
++pos;
return err(
error{ token_start, pos, "unexpected end of real, expecting exponent" });
}
break;
}
else if(expecting_exponent)
{
expecting_exponent = false;
}

contains_leading_digit = true;

++pos;
}

if(expecting_exponent)
{
++pos;
return err(error{ token_start, pos, "unexpected end of real, expecting exponent" });
}

/* Tokens beginning with - are ambiguous; it's only a negative number if it has numbers
* to follow. */
* to follow.
* TODO: handle numbers starting with `+` */
if(file[token_start] != '-' || (pos - token_start) >= 1)
{
require_space = true;
++pos;
if(contains_dot)
if(contains_dot || is_scientific)
{
return ok(token{ token_start,
pos - token_start,
Expand Down
17 changes: 17 additions & 0 deletions compiler+runtime/src/cpp/jank/read/parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ namespace jank::read::parse
return parse_integer();
case lex::token_kind::real:
return parse_real();
case lex::token_kind::ratio:
return parse_ratio();
case lex::token_kind::string:
return parse_string();
case lex::token_kind::escaped_string:
Expand Down Expand Up @@ -1166,6 +1168,21 @@ namespace jank::read::parse
token };
}

processor::object_result processor::parse_ratio()
{
auto const token(token_current->expect_ok());
++token_current;
auto const &ratio_data(boost::get<lex::ratio>(token.data));
if(ratio_data.denominator == 0)
{
return err(error{ token.pos, "Divide by zero" });
}
return object_source_info{ make_box<obj::real>(static_cast<native_real>(ratio_data.numerator)
/ ratio_data.denominator),
token,
token };
}

processor::object_result processor::parse_real()
{
auto const token(token_current->expect_ok());
Expand Down
Loading