diff --git a/src/include/keywords.hh b/src/include/keywords.hh new file mode 100644 index 0000000..41eea1a --- /dev/null +++ b/src/include/keywords.hh @@ -0,0 +1,43 @@ +#pragma once + +#define fn auto +#define let auto +#define mod namespace +#define pub +#define self (*this) +#define self__Self (this Self & self) +#define type using +#define use using +#define enum enum class +#define match switch +#define arm(pat, ...) \ + case pat: \ + __VA_ARGS__; \ + break + +#define makeSelf(...) \ + type Self = __VA_ARGS__ + +#define loop while (1) + +// clang-format off +#define RUSTPP_UNIQ__(a, b) a ## b +#define RUSTPP_UNIQ_(a, b) RUSTPP_UNIQ__(a, b) +#define RUSTPP_UNIQ(name) RUSTPP_UNIQ_(name, __LINE__) +// clang-format on + +#define rustpp_for(value, iter) \ + auto RUSTPP_UNIQ (iterator) = iter.into_iter (); \ + for (auto value = RUSTPP_UNIQ (iterator).next (); value.is_some (); value = RUSTPP_UNIQ (iterator).next ()) + + +#ifndef I_AM_RUSTPP_RUNTIME + +#define main rustpp__main +#define new __rustpp__new + +#ifndef NO_RUSTPP_FOR +#define for(...) rustpp_for (__VA_ARGS__) +#endif /* NO_RUSTPP_FOR */ + +#endif /* I_AM_RUSTPP_RUNTIME */ diff --git a/src/include/panic.hh b/src/include/panic.hh new file mode 100644 index 0000000..b056635 --- /dev/null +++ b/src/include/panic.hh @@ -0,0 +1,28 @@ +//! Unwinding panic support +#pragma once + +#include +#include // IWYU pragma: export +#include + +namespace panic { + + class Panic: std::exception { + public: + // std::stacktrace stack; + std::string message; + Panic (std::string message) : message (message) { + // stack = std::stacktrace::current(); + } + + constexpr const char *what () { + return message.c_str (); + } + }; +} // namespace panic + + +#define panic(...) \ + do { \ + throw panic::Panic { std::format (__VA_ARGS__) }; \ + } while (false) diff --git a/src/include/primitives.hh b/src/include/primitives.hh new file mode 100644 index 0000000..3b114ba --- /dev/null +++ b/src/include/primitives.hh @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +using u8 = uint8_t; +using i8 = int8_t; + +using u16 = uint16_t; +using i16 = int16_t; + +using u32 = uint32_t; +using i32 = int32_t; + +using u64 = uint64_t; +using i64 = int64_t; + +using usize = size_t; +using isize = ssize_t; + +using f32 = float; +using f64 = double; diff --git a/src/include/rust.hh b/src/include/rust.hh new file mode 100644 index 0000000..edf1aa4 --- /dev/null +++ b/src/include/rust.hh @@ -0,0 +1,350 @@ +#pragma once + +#include +#include // IWYU pragma: export + +#include "panic.hh" // IWYU pragma: export +#include "primitives.hh" // IWYU pragma: export + +// no reorder +#include "keywords.hh" // IWYU pragma: export + +type Cstr = char *; + +/** The main function: does main things */ +fn rustpp__main () -> i32; + +mod termination { + class Termination { + fn return_value () -> int { + return 0; + } + }; +} + +mod option { + template + class Option: termination::Termination { + union { + u8 None = 0; + T Some; + } value; + enum variant : bool { + None = 0, + Some, + } variant; + + public: + makeSelf (Option); + + pub static fn Some (T value) -> Self { + Self op; + op.value.Some = value; + op.variant = variant::Some; + return op; + } + + pub static fn None (T *_type = (T *) (0)) -> Self { + Self op; + op.value.None = 0; + op.variant = variant::None; + return op; + } + + pub fn return_value () -> int { + return self.is_some (); + } + + pub fn is_some () -> bool { + return variant == variant::Some; + } + + pub fn is_none () -> bool { + return variant == variant::None; + } + + pub operator bool () { + return this->is_some (); + } + + pub fn unwrap () -> T { + match (variant) { + arm (variant::Some, return value.Some); + arm (variant::None, panic ("Called Option::unwrap() on a None value")); + } + } + + template + pub fn map (U (f) (T)) -> Option { + match (variant) { + arm (variant::Some, return Some (f (value.Some))); + arm (variant::None, return None ()); + } + } + }; + + /// Constructs an Option with `variant` None + /// + /// Takes an optional (never-dereferenced) pointer argument, for type inference. + template + fn None (T *_type = (T *) (0)) -> Option { + return Option::None (); + } + + /// Constructs an option with `variant` Some + template + fn Some (T value) -> Option { + return Option::Some (value); + } +} + +mod result { + template + class Result { + union { + T Ok; + E Err; + } value; + enum variant { + Ok, + Err, + } variant; + + public: + makeSelf (Result); + + // TODO: destructor for Result + + pub static fn Ok (T value) -> Self { + Self result; + result.value.Ok = value; + result.variant = variant::Ok; + return result; + } + + pub static fn Err (E error) -> Self { + Self result; + result.value.Err = error; + result.variant = variant::Err; + return result; + } + + pub fn is_ok () -> bool { + return variant == variant::Ok; + } + + pub fn is_err () -> bool { + return variant == variant::Err; + } + + pub fn unwrap () -> T { + match (variant) { + arm (variant::Ok, return value.Ok); + arm (variant::Err, panic ("Called Result::unwrap() on Err value")); + } + } + + pub fn unwrap_err () -> E { + match (variant) { + arm (variant::Ok, panic ("Called Result::unwrap_err() on Ok value")); + arm (variant::Err, return value.Err); + } + } + }; +} + +mod ptr { + template + struct Nonnull { + T *value; + makeSelf (Nonnull); + + pub static fn __rustpp__new (T *value) -> option::Option { + switch (value) { + case nullptr: + return option::Some ({ value }); + default: + return option::None (&value); + } + } + + fn operator* ()->T & { + return *value; + } + }; + + template + fn nonnull (T * value) -> option::Option> { + switch (value) { + case nullptr: + return option::Some (value); + default: + return option::None (&value); + } + } + + template + fn nonnull_unchecked (T * value) -> Nonnull { + return { value }; + } +} + +mod iter { + template + class Iterator { + public: + virtual fn next () -> option::Option = 0; + // TODO: default methods for Iterator + }; +} + +mod slice { + template + class Iter: public iter::Iterator { + T *head; + T *tail; + + Iter (T *head, T *tail) : head (head), tail (tail) {} + + public: + makeSelf (Iter); + + static fn __rustpp__new (T *head, usize len) -> Self { + return { head, head + len }; + } + + fn next () -> option::Option override { + if (head < tail) + return option::Some (head++); + else + return option::None (); + } + + fn into_iter () -> Self & { + return self; + } + }; + + template + struct Slice { + T *ptr; + usize len; + + makeSelf (Slice); + fn into_iter () -> Iter { + return Iter::__rustpp__new (self.ptr, self.len); + } + }; +} + +mod vec { + /// Drains a heap allocated array, returning elements by copy + template + class Drain: public iter::Iterator { + T *allocation; + T *head; + T *tail; + + public: + Drain () : allocation (nullptr), head (nullptr), tail (nullptr) {} + Drain (T *allocation, usize len) : allocation (allocation), + head (allocation), + tail (allocation + len) {} + ~Drain () { + free (allocation); + } + + + fn next () -> option::Option override { + if (head < tail) { + return option::Some (*head++); + } + if (allocation) { + free(allocation); + allocation = nullptr; + } + return option::None (); + } + }; + + + template + struct Vec { + T *ptr; + usize len; + usize cap; + + makeSelf (Vec); + + static fn __rustpp__new () -> Self { + return {}; + } + + fn resize (usize cap) -> usize { + ptr = (T *) realloc ((void *) ptr, cap); + if (!ptr) { + panic ("Failed to resize Vec from {} to {}.", self.cap, cap); + } + self.cap = cap; + return self.cap; + } + + fn _grow () -> usize { + switch (len) { + case 0: + return self.resize (8); + default: + return self.resize ((cap << 1) - cap); + } + } + + fn drop () { + free (ptr); + self = {}; + } + + fn push (T value) { + self._grow (); + ptr[len++] = value; + } + + fn pop () -> option::Option { + use option::Some, option::None; + if (len == 0) { + return None (ptr); + } + + let value = ptr[--len]; + return Some (value); + } + + fn as_slice () -> slice::Slice { + return slice::Slice { ptr, len }; + } + + fn iter () -> slice::Iter { + return self.as_slice ().into_iter (); + } + + fn into_iter () -> Drain { + let drain = Drain (self.ptr, self.len); + self = {}; + return drain; + } + }; +} + +mod env { + /// Gets the environment variables + fn args () -> slice::Slice; +} + + +mod prelude { + use slice::Slice; + use option::Option, option::Some, option::None; + use result::Result; +} + + +using mod prelude; diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..8f0b079 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,25 @@ +#include + +#include "rust.hh" + +fn main () -> i32 { + let v = vec::Vec::new (); + + v.push (10); + v.push (20); + v.push (30); + + std::println("Printing contents of v"); + for (x, v) { + std::println ("{}", x.unwrap ()); + } + + // This is okay, because the previous for loop moved out of v + // leaving it default-initialized. + std::println("Printing contents of v"); + for (x, v) { + std::println ("{}", x.unwrap ()); + } + + return 0; +} diff --git a/src/rust.cc b/src/rust.cc new file mode 100644 index 0000000..827494a --- /dev/null +++ b/src/rust.cc @@ -0,0 +1,25 @@ +#include "panic.hh" +#define I_AM_RUSTPP_RUNTIME +#include + +#include "rust.hh" + +namespace { + slice::Slice program_args = {}; +} + +fn main (int argc, char **argv) -> int { + program_args = { (Cstr *) argv, (usize) argc }; + try { + return rustpp__main (); + } catch (panic::Panic p) { + std::println ("Thread exited with explicit panic: {}", p.what ()); + } +} + +// Environment +namespace env { + fn args () -> slice::Slice { + return program_args; + } +} // namespace env