diff --git a/.clang-tidy b/.clang-tidy index 712f3ca27..3580b03de 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -31,6 +31,7 @@ Checks: ' -misc-unused-parameters, -misc-const-correctness, -misc-confusable-identifiers, + -misc-const-correctness, modernize-*, -modernize-avoid-c-arrays, diff --git a/.gitmodules b/.gitmodules index 0a0b23215..b85a7cf22 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/onqtam/doctest.git [submodule "3rdparty/SafeInt"] path = 3rdparty/SafeInt - url = https://github.com/dcleblanc/SafeInt + url = https://github.com/rsmmr/SafeInt.git [submodule "3rdparty/ArticleEnumClass-v2"] path = 3rdparty/ArticleEnumClass-v2 url = https://github.com/Dalzhim/ArticleEnumClass-v2 diff --git a/3rdparty/SafeInt b/3rdparty/SafeInt index a5408ba2c..9d82c49d8 160000 --- a/3rdparty/SafeInt +++ b/3rdparty/SafeInt @@ -1 +1 @@ -Subproject commit a5408ba2c025ec99a7afb6ccca907d5a263242a5 +Subproject commit 9d82c49d8f3ebfc34fb51f440243e085eb998558 diff --git a/CHANGES b/CHANGES index 99ea2ccd4..5babf0cae 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,31 @@ +1.7.0-dev.78 | 2023-01-27 11:16:01 +0100 + + * GH-1123: Support arbitrary expression as argument to type + constructors, such as `interval(...)`. (Robin Sommer, Corelight) + + So far we used constructor expressions like `interval(...)` to create + *constants* of the given type, and for that we required that the + argument was a single atomic value. The result was that these + constructor expressions were really more like literals for the + corresponding types than "normal" expressions. While that's useful + internally, it's confusing to the user. This commits changes that + to support arbitrary expressions as arguments. + + To make this change without loosing a way to create actual constants + (which we need at some places), we implement this in two stages: the + parser initially turns such `interval(...)` expressions into call + operators[1] that the types now define for each desired constructor. We + then extend the normalizer with a new constants folding pass that + turns the call expressions into constants if possible. + + The new constant folder remains limited to the cases we need for + this use case, but we'll be able to expand that later to more + general folding. + + * Fix bug in cast from `real` to `interval`. (Robin Sommer, Corelight) + + * Add anchors to FAQ items in docs [skip CI]. (Benjamin Bannier, Corelight) + 1.7.0-dev.53 | 2023-01-25 09:39:02 +0100 * Add stringification to UnitContext. (Benjamin Bannier, Corelight) diff --git a/VERSION b/VERSION index 09de13542..8e625cc91 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.0-dev.53 +1.7.0-dev.78 diff --git a/doc/autogen/types/error.rst b/doc/autogen/types/error.rst index d9be01083..6a328c307 100644 --- a/doc/autogen/types/error.rst +++ b/doc/autogen/types/error.rst @@ -4,3 +4,9 @@ Retrieves the textual description associated with the error. +.. rubric:: Operators + +.. spicy:operator:: error::Call error error(string) + + Creates an error with the given message. + diff --git a/doc/autogen/types/integer.rst b/doc/autogen/types/integer.rst index a2630bfcb..c594cedf2 100644 --- a/doc/autogen/types/integer.rst +++ b/doc/autogen/types/integer.rst @@ -12,6 +12,70 @@ Computes the bit-wise 'xor' of the two integers. +.. spicy:operator:: integer::Call int<16> int16(int) + + Creates a 16-bit signed integer value. + +.. spicy:operator:: integer::Call int<16> int16(uint) + + Creates a 16-bit signed integer value. + +.. spicy:operator:: integer::Call int<32> int32(int) + + Creates a 32-bit signed integer value. + +.. spicy:operator:: integer::Call int<32> int32(uint) + + Creates a 32-bit signed integer value. + +.. spicy:operator:: integer::Call int<64> int64(int) + + Creates a 64-bit signed integer value. + +.. spicy:operator:: integer::Call int<64> int64(uint) + + Creates a 64-bit signed integer value. + +.. spicy:operator:: integer::Call int<8> int8(int) + + Creates a 8-bit signed integer value. + +.. spicy:operator:: integer::Call int<8> int8(uint) + + Creates a 8-bit signed integer value. + +.. spicy:operator:: integer::Call uint<16> uint16(int) + + Creates a 16-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<16> uint16(uint) + + Creates a 16-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<32> uint32(int) + + Creates a 32-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<32> uint32(uint) + + Creates a 32-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<64> uint64(int) + + Creates a 64-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<64> uint64(uint) + + Creates a 64-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<8> uint8(int) + + Creates a 8-bit unsigned integer value. + +.. spicy:operator:: integer::Call uint<8> uint8(uint) + + Creates a 8-bit unsigned integer value. + .. spicy:operator:: integer::Cast bool cast(int) Converts the value to a boolean by comparing against zero @@ -220,6 +284,10 @@ Inverts the sign of the integer. +.. spicy:operator:: integer::SignNeg int op:- t:uint op: + + Inverts the sign of the integer. + .. spicy:operator:: integer::Sum int t:int op:+ t:int Computes the sum of the integers. diff --git a/doc/autogen/types/interval.rst b/doc/autogen/types/interval.rst index a26d6395a..0f0820ff9 100644 --- a/doc/autogen/types/interval.rst +++ b/doc/autogen/types/interval.rst @@ -10,6 +10,28 @@ .. rubric:: Operators +.. spicy:operator:: interval::Call interval interval(int) + + Creates an interval interpreting the argument as number of seconds. + +.. spicy:operator:: interval::Call interval interval(real) + + Creates an interval interpreting the argument as number of seconds. + +.. spicy:operator:: interval::Call interval interval(uint) + + Creates an interval interpreting the argument as number of seconds. + +.. spicy:operator:: interval::Call interval interval_ns(int) + + Creates an interval interpreting the argument as number of + nanoseconds. + +.. spicy:operator:: interval::Call interval interval_ns(uint) + + Creates an interval interpreting the argument as number of + nanoseconds. + .. spicy:operator:: interval::Difference interval t:interval op:- t:interval Returns the difference of the intervals. diff --git a/doc/autogen/types/port.rst b/doc/autogen/types/port.rst index b12597cbc..23580a351 100644 --- a/doc/autogen/types/port.rst +++ b/doc/autogen/types/port.rst @@ -6,6 +6,10 @@ .. rubric:: Operators +.. spicy:operator:: port::Call port port(uint<16>, enum) + + Creates a port instance. + .. spicy:operator:: port::Equal bool t:port op:== t:port Compares two port values. diff --git a/doc/autogen/types/stream.rst b/doc/autogen/types/stream.rst index 5cd610e49..a6312a8b8 100644 --- a/doc/autogen/types/stream.rst +++ b/doc/autogen/types/stream.rst @@ -38,6 +38,10 @@ Returns an iterator to the beginning of the container's content. +.. spicy:operator:: stream::Call stream stream(bytes) + + Creates a stream instance preinitialized with the given data. + .. spicy:operator:: stream::End end() Returns an iterator to the end of the container's content. diff --git a/doc/autogen/types/time.rst b/doc/autogen/types/time.rst index 777bbe309..83bb94ddb 100644 --- a/doc/autogen/types/time.rst +++ b/doc/autogen/types/time.rst @@ -12,6 +12,26 @@ .. rubric:: Operators +.. spicy:operator:: time::Call time time(int) + + Creates an time interpreting the argument as number of seconds. + +.. spicy:operator:: time::Call time time(real) + + Creates an time interpreting the argument as number of seconds. + +.. spicy:operator:: time::Call time time(uint) + + Creates an time interpreting the argument as number of seconds. + +.. spicy:operator:: time::Call time time_ns(int) + + Creates an time interpreting the argument as number of nanoseconds. + +.. spicy:operator:: time::Call time time_ns(uint) + + Creates an time interpreting the argument as number of nanoseconds. + .. spicy:operator:: time::Difference interval t:time op:- t:time Returns the difference of the times. diff --git a/hilti/runtime/CMakeLists.txt b/hilti/runtime/CMakeLists.txt index 34befa505..acdbd3c65 100644 --- a/hilti/runtime/CMakeLists.txt +++ b/hilti/runtime/CMakeLists.txt @@ -32,6 +32,7 @@ set(SOURCES src/library.cc src/logging.cc src/main.cc + src/safe-math.cc src/type-info.cc src/types/address.cc src/types/bytes.cc diff --git a/hilti/runtime/include/safe-math.h b/hilti/runtime/include/safe-math.h new file mode 100644 index 000000000..23ac5fec9 --- /dev/null +++ b/hilti/runtime/include/safe-math.h @@ -0,0 +1,19 @@ +// Copyright (c) 2020-2022 by the Zeek Project. See LICENSE for details. +// +// Wrapper around functionality from 3rdparty's safe-math that we need. This +// needs to be in a separate implementation file because one cannot include +// both SafeInt.h and safe-math.h at the same time. + +#pragma once + +#include + +namespace hilti::rt::integer { + +/** + * Negates an unsigned value, returning a signed value. Will through a + * `OutOfRange` if not possible. + */ +extern int64_t safe_negate(uint64_t x); + +} // namespace hilti::rt::integer diff --git a/hilti/runtime/include/types/interval.h b/hilti/runtime/include/types/interval.h index aa43ad223..ee19afc0d 100644 --- a/hilti/runtime/include/types/interval.h +++ b/hilti/runtime/include/types/interval.h @@ -31,7 +31,7 @@ class Interval { * * @param nsecs interval in nanoseconds. */ - explicit Interval(hilti::rt::integer::safe nsecs, NanosecondTag /*unused*/) : _nsecs(nsecs) {} + explicit Interval(const hilti::rt::integer::safe& nsecs, NanosecondTag /*unused*/) : _nsecs(nsecs) {} /** * Constructs an interval from a double value. @@ -73,9 +73,11 @@ class Interval { Interval operator+(const Interval& other) const { return Interval(_nsecs + other._nsecs, NanosecondTag()); } Interval operator-(const Interval& other) const { return Interval(_nsecs - other._nsecs, NanosecondTag()); } - Interval operator*(hilti::rt::integer::safe i) const { return Interval(_nsecs * i, NanosecondTag()); } + Interval operator*(const hilti::rt::integer::safe& i) const { + return Interval(_nsecs * i, NanosecondTag()); + } - Interval operator*(hilti::rt::integer::safe i) const { + Interval operator*(const hilti::rt::integer::safe& i) const { return Interval(_nsecs * i.Ref(), NanosecondTag()); } diff --git a/hilti/runtime/include/types/stream.h b/hilti/runtime/include/types/stream.h index 662ec256f..d2ceb7583 100644 --- a/hilti/runtime/include/types/stream.h +++ b/hilti/runtime/include/types/stream.h @@ -90,17 +90,18 @@ class Chunk { using Array = std::pair>; using Vector = std::vector; - Chunk(Offset o, std::array d, Size n) : _offset(o), _data(std::make_pair(n, d)) {} - Chunk(Offset o, Vector&& d) : _offset(o), _data(std::move(d)) {} - Chunk(Offset o, const View& d); - Chunk(Offset o, const std::string& s); + Chunk(const Offset& o, std::array d, const Size& n) + : _offset(o), _data(std::make_pair(n, d)) {} + Chunk(const Offset& o, Vector&& d) : _offset(o), _data(std::move(d)) {} + Chunk(const Offset& o, const View& d); + Chunk(const Offset& o, const std::string& s); template Chunk(Offset o, std::array d) : Chunk(_fromArray(o, std::move(d))) {} - Chunk(Offset o, const char* d, Size n) : Chunk(_fromArray(o, d, n)) {} + Chunk(const Offset& o, const char* d, const Size& n) : Chunk(_fromArray(o, d, n)) {} // Constructs a gap chunk which signifies empty data. - Chunk(Offset o, size_t len) : _offset(o), _data(Gap{len}) {} + Chunk(const Offset& o, size_t len) : _offset(o), _data(Gap{len}) {} Chunk(const Chunk& other) : _offset(other._offset), _data(other._data) {} Chunk(Chunk&& other) noexcept @@ -121,7 +122,7 @@ class Chunk { Offset offset() const { return _offset; } Offset endOffset() const { return _offset + size(); } bool isGap() const { return std::holds_alternative(_data); } - bool inRange(Offset offset) const { return offset >= _offset && offset < endOffset(); } + bool inRange(const Offset& offset) const { return offset >= _offset && offset < endOffset(); } const Byte* data() const { if ( auto a = std::get_if(&_data) ) @@ -135,7 +136,7 @@ class Chunk { hilti::rt::cannot_be_reached(); } - const Byte* data(Offset offset) const { + const Byte* data(const Offset& offset) const { assert(inRange(offset)); return data() + (offset - _offset).Ref(); } @@ -187,7 +188,7 @@ class Chunk { // only from chain so that it can track any changes. friend class Chain; - void trim(Offset o); + void trim(const Offset& o); // Update offset for current chunk and all others linked from it. void setOffset(Offset o) { @@ -230,7 +231,7 @@ class Chunk { void clearNext() { _next = nullptr; } private: - inline Chunk _fromArray(Offset o, const char* d, Size n) { + inline Chunk _fromArray(const Offset& o, const char* d, const Size& n) { auto ud = reinterpret_cast(d); if ( n <= Chunk::SmallBufferSize ) { @@ -276,7 +277,7 @@ class Chain : public intrusive_ptr::ManagedObject { Size size() const { return (endOffset() - offset()).Ref(); } bool isFrozen() const { return _state == State::Frozen; } bool isValid() const { return _state != State::Invalid; } - bool inRange(Offset o) const { return o >= offset() && o < endOffset(); } + bool inRange(const Offset& o) const { return o >= offset() && o < endOffset(); } Offset offset() const { return _head_offset; } Offset endOffset() const { return _tail ? _tail->endOffset() : _head_offset; } @@ -286,16 +287,16 @@ class Chain : public intrusive_ptr::ManagedObject { // allowing that to be found more quickly. If given, *hint_prev* must be // pointing to a current chunk of the chain, but it's ok if it's // non-helpful for finding the target (i.e., pointing to a later chunk). - const Chunk* findChunk(Offset offset, const Chunk* hint_prev = nullptr) const; - Chunk* findChunk(Offset offset, Chunk* hint_prev = nullptr); + const Chunk* findChunk(const Offset& offset, const Chunk* hint_prev = nullptr) const; + Chunk* findChunk(const Offset& offset, Chunk* hint_prev = nullptr); // Returns a pointer to the byte at a given offset. Returns null if // offset is out of range. See find() for semantics of *hint_prev*. - const Byte* data(Offset offset, Chunk* hint_prev = nullptr) const; + const Byte* data(const Offset& offset, Chunk* hint_prev = nullptr) const; SafeConstIterator begin() const; SafeConstIterator end() const; - SafeConstIterator at(Offset offset) const; + SafeConstIterator at(const Offset& offset) const; UnsafeConstIterator unsafeBegin() const; UnsafeConstIterator unsafeEnd() const; @@ -306,7 +307,7 @@ class Chain : public intrusive_ptr::ManagedObject { void append(std::unique_ptr chunk); void append(Chain&& other); - void trim(Offset offset); + void trim(const Offset& offset); void trim(const SafeConstIterator& i); void trim(const UnsafeConstIterator& i); @@ -424,7 +425,7 @@ class SafeConstIterator { } /** Advances the iterator by a given number of stream. */ - auto& operator+=(integer::safe i) { + auto& operator+=(const integer::safe& i) { _increment(i); return *this; } @@ -443,7 +444,7 @@ class SafeConstIterator { } /** Moves back the iterator by a given number of stream. */ - auto& operator-=(integer::safe i) { + auto& operator-=(const integer::safe& i) { _decrement(i); return *this; } @@ -452,14 +453,14 @@ class SafeConstIterator { auto operator*() const { return _dereference(); } /** Return a new iterator advanced by a given number of bytes. */ - auto operator+(integer::safe i) const { + auto operator+(const integer::safe& i) const { auto x = *this; x._increment(i); return x; } /** Returns a new iterator moved back by a given number of bytes. */ - auto operator-(integer::safe i) const { + auto operator-(const integer::safe& i) const { auto x = *this; x._decrement(i); return x; @@ -577,7 +578,7 @@ class SafeConstIterator { const Chain* chain() const { return _chain.get(); } private: - SafeConstIterator(ConstChainPtr chain, Offset offset, const Chunk* chunk) + SafeConstIterator(ConstChainPtr chain, const Offset& offset, const Chunk* chunk) : _chain(std::move(chain)), _offset(offset), _chunk(chunk) { assert(! isUnset()); } @@ -602,7 +603,7 @@ class SafeConstIterator { throw InvalidIterator("incompatible iterators"); } - void _increment(integer::safe n) { + void _increment(const integer::safe& n) { if ( ! _chain ) throw InvalidIterator("unbound stream iterator"); @@ -618,7 +619,7 @@ class SafeConstIterator { // chunk will be null if we're pointing beyond the end. } - void _decrement(integer::safe n) { + void _decrement(const integer::safe& n) { if ( ! _chain ) throw InvalidIterator("unbound stream iterator"); @@ -747,7 +748,7 @@ class UnsafeConstIterator { } /** Moves back the iterator by a given number of stream. */ - auto& operator-=(integer::safe i) { + auto& operator-=(const integer::safe& i) { _decrement(i); return *this; } @@ -756,14 +757,14 @@ class UnsafeConstIterator { auto operator*() const { return _dereference(); } /** Return a new iterator advanced by a given number of bytes. */ - auto operator+(integer::safe i) const { + auto operator+(const integer::safe& i) const { auto x = *this; x._increment(i); return x; } /** Return a new iterator moved back by a given number of bytes. */ - auto operator-(integer::safe i) const { + auto operator-(const integer::safe& i) const { auto x = *this; x._decrement(i); return x; @@ -857,17 +858,17 @@ class UnsafeConstIterator { const Chain* chain() const { return _chain; } private: - UnsafeConstIterator(const ConstChainPtr& chain, Offset offset, const Chunk* chunk) + UnsafeConstIterator(const ConstChainPtr& chain, const Offset& offset, const Chunk* chunk) : _chain(chain.get()), _offset(offset), _chunk(chunk) { assert(! isUnset()); } - UnsafeConstIterator(const Chain* chain, Offset offset, const Chunk* chunk) + UnsafeConstIterator(const Chain* chain, const Offset& offset, const Chunk* chunk) : _chain(chain), _offset(offset), _chunk(chunk) { assert(! isUnset()); } - void _increment(integer::safe n) { + void _increment(const integer::safe& n) { _offset += n; if ( _chunk && _offset < _chunk->endOffset() ) @@ -876,7 +877,7 @@ class UnsafeConstIterator { _chunk = _chain->findChunk(_offset, _chunk); } - void _decrement(integer::safe n) { + void _decrement(const integer::safe& n) { _offset -= n; if ( _chunk && _offset > _chunk->offset() ) @@ -955,7 +956,7 @@ inline SafeConstIterator Chain::end() const { return {ConstChainPtr(intrusive_ptr::NewRef(), this), endOffset(), _tail}; } -inline SafeConstIterator Chain::at(Offset offset) const { +inline SafeConstIterator Chain::at(const Offset& offset) const { return {ConstChainPtr(intrusive_ptr::NewRef(), this), offset, findChunk(offset)}; } @@ -1205,7 +1206,7 @@ class View { * * @param i the number of stream to advance. */ - View advance(integer::safe i) const { return View(begin() + i, _end); } + View advance(const integer::safe& i) const { return View(begin() + i, _end); } /** * Advances the view to the next, none gap offset. This always advances at least by one byte. @@ -1241,7 +1242,7 @@ class View { * @param from offset of start of subrange, relative to beginning of view * @param to offset of one beyond end of subrange, relative to beginning of view */ - View sub(Offset from, Offset to) const { return View(begin() + from, begin() + to); } + View sub(const Offset& from, const Offset& to) const { return View(begin() + from, begin() + to); } /** * Extracts subrange of stream from the beginning of the view, returned as @@ -1249,10 +1250,10 @@ class View { * * @param to of one beyond end of subrange, relative to beginning of view */ - View sub(Offset to) const { return View(begin(), begin() + to); } + View sub(const Offset& to) const { return View(begin(), begin() + to); } /** Returns an iterator representing an offset inside the view's data */ - SafeConstIterator at(Offset offset) const { return begin() + (offset - begin().offset()); } + SafeConstIterator at(const Offset& offset) const { return begin() + (offset - begin().offset()); } /** * Returns a new view moves the beginning to a subsequent iterator while @@ -1276,7 +1277,7 @@ class View { * at a specified offset from that beginning. The returned view will not * be able to expand any further. */ - View limit(Offset incr) const { return View(begin(), begin() + incr); } + View limit(const Offset& incr) const { return View(begin(), begin() + incr); } /** * Extracts a fixed number of stream from the view. @@ -1442,7 +1443,7 @@ class Stream { * Creates an instance from an existing memory block. The data * will be copied if set, otherwise a gap will be recorded. */ - Stream(const char* d, Size n); + Stream(const char* d, const Size& n); /** * Creates an instance from an existing stream view. * @param d `View` to create the stream from @@ -1566,7 +1567,7 @@ class Stream { * Returns an iterator representing a specific offset. * @param offset offset to use for the created iterator */ - SafeConstIterator at(Offset offset) const { return _chain->at(offset); } + SafeConstIterator at(const Offset& offset) const { return _chain->at(offset); } /** * Returns a view representing the entire instance. diff --git a/hilti/runtime/include/types/time.h b/hilti/runtime/include/types/time.h index df2d9920d..5c5c5a1f9 100644 --- a/hilti/runtime/include/types/time.h +++ b/hilti/runtime/include/types/time.h @@ -30,7 +30,7 @@ class Time { * * @param nsecs interval in nanoseconds. */ - explicit Time(hilti::rt::integer::safe nsecs, NanosecondTag /*unused*/) : _nsecs(nsecs) {} + explicit Time(const hilti::rt::integer::safe& nsecs, NanosecondTag /*unused*/) : _nsecs(nsecs) {} /** * Constructs a time from a double value. diff --git a/hilti/runtime/src/safe-math.cc b/hilti/runtime/src/safe-math.cc new file mode 100644 index 000000000..8dc689478 --- /dev/null +++ b/hilti/runtime/src/safe-math.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2020-2022 by the Zeek Project. See LICENSE for details. + +#include +#include + +using namespace hilti::rt; + +[[noreturn]] inline void safe_math_fail(const char* msg) { throw OutOfRange("integer value out of range"); } + +#define SAFE_MATH_FAIL_DEFINED +extern "C" { +#include +} + +int64_t integer::safe_negate(uint64_t x) { return safe_sub_int64_uint64(0, x); } diff --git a/hilti/runtime/src/tests/address.cc b/hilti/runtime/src/tests/address.cc index 0e14ce471..d38531371 100644 --- a/hilti/runtime/src/tests/address.cc +++ b/hilti/runtime/src/tests/address.cc @@ -70,7 +70,10 @@ TEST_CASE("conversions to and from `std::string`") { TEST_CASE("constructs from an `::in_addr4`") { CHECK_EQ(std::string(Address(*make_in_addr("1.2.3.4"))), "1.2.3.4"); } TEST_CASE("constructs from an `::in6_addr`") { - CHECK_EQ(std::string(Address(*make_in6_addr("::4996:2d2:0:0:4996:2d2"))), "::4996:2d2:0:0:4996:2d2"); + std::string addr = std::string(Address(*make_in6_addr("::4996:2d2:0:0:4996:2d2"))); + auto is_correct = (addr == "::4996:2d2:0:0:4996:2d2" || addr == "0:0:4996:2d2::4996:2d2"); // Alpine has been seen to return the latter + + CHECK(is_correct); } TEST_CASE("constructs from binary representation of an IPv4 address") { @@ -80,7 +83,11 @@ TEST_CASE("constructs from binary representation of an IPv4 address") { TEST_CASE("constructs from binary representation of an IPv6 address") { CHECK_EQ(Address(1234567890, 1234567890).family(), AddressFamily::IPv6); - CHECK_EQ(std::string(Address(1234567890, 1234567890)), "::4996:2d2:0:0:4996:2d2"); + + std::string addr = Address(1234567890, 1234567890); + bool is_correct = (addr == "::4996:2d2:0:0:4996:2d2" || + addr == "0:0:4996:2d2::4996:2d2"); // Alpine has been seen to return the latter + CHECK(is_correct); } TEST_CASE("family") { diff --git a/hilti/runtime/src/types/stream.cc b/hilti/runtime/src/types/stream.cc index a3228cf84..4c32b4496 100644 --- a/hilti/runtime/src/types/stream.cc +++ b/hilti/runtime/src/types/stream.cc @@ -9,7 +9,7 @@ using namespace hilti::rt; using namespace hilti::rt::stream; using namespace hilti::rt::stream::detail; -Chunk::Chunk(Offset offset, const View& d) : _offset(offset) { +Chunk::Chunk(const Offset& offset, const View& d) : _offset(offset) { if ( d.size() <= SmallBufferSize ) { std::array a{}; d.copyRaw(a.data()); @@ -23,7 +23,7 @@ Chunk::Chunk(Offset offset, const View& d) : _offset(offset) { } } -Chunk::Chunk(Offset offset, const std::string& s) : _offset(offset) { +Chunk::Chunk(const Offset& offset, const std::string& s) : _offset(offset) { if ( s.size() <= SmallBufferSize ) { std::array a{}; memcpy(a.data(), s.data(), s.size()); @@ -37,7 +37,7 @@ Chunk::Chunk(Offset offset, const std::string& s) : _offset(offset) { } } -void Chunk::trim(Offset o) { +void Chunk::trim(const Offset& o) { assert(o >= _offset && o < _offset + size()); if ( auto a = std::get_if(&_data) ) { auto begin = a->second.data() + (o - _offset).Ref(); @@ -54,7 +54,7 @@ void Chunk::trim(Offset o) { _offset = o; } -const Chunk* Chain::findChunk(Offset offset, const Chunk* hint_prev) const { +const Chunk* Chain::findChunk(const Offset& offset, const Chunk* hint_prev) const { _ensureValid(); const Chunk* c = _head.get(); @@ -71,7 +71,7 @@ const Chunk* Chain::findChunk(Offset offset, const Chunk* hint_prev) const { return c; } -Chunk* Chain::findChunk(Offset offset, Chunk* hint_prev) { +Chunk* Chain::findChunk(const Offset& offset, Chunk* hint_prev) { _ensureValid(); Chunk* c = _head.get(); @@ -88,7 +88,7 @@ Chunk* Chain::findChunk(Offset offset, Chunk* hint_prev) { return c; } -const Byte* Chain::data(Offset offset, Chunk* hint_prev) const { +const Byte* Chain::data(const Offset& offset, Chunk* hint_prev) const { auto c = findChunk(offset, hint_prev); if ( ! c ) throw InvalidIterator("stream iterator outside of valid range"); @@ -126,7 +126,7 @@ void Chain::append(Chain&& other) { other.reset(); } -void Chain::trim(Offset offset) { +void Chain::trim(const Offset& offset) { _ensureValid(); // We search the first chunk that's containing the desired position, @@ -425,7 +425,7 @@ std::optional View::nextBlock(std::optional current) const { Stream::Stream(const Bytes& d) : Stream(Chunk(0, d.str())) {} -Stream::Stream(const char* d, Size n) : Stream() { append(d, n); } +Stream::Stream(const char* d, const Size& n) : Stream() { append(d, n); } void Stream::append(Bytes&& data) { if ( data.isEmpty() ) diff --git a/hilti/toolchain/CMakeLists.txt b/hilti/toolchain/CMakeLists.txt index 94db253ef..2fa826416 100644 --- a/hilti/toolchain/CMakeLists.txt +++ b/hilti/toolchain/CMakeLists.txt @@ -83,6 +83,7 @@ set(SOURCES src/compiler/plugin.cc src/compiler/unit.cc src/compiler/visitors/coercer.cc + src/compiler/visitors/constant-folder.cc src/compiler/visitors/normalizer.cc src/compiler/visitors/printer.cc src/compiler/visitors/renderer.cc diff --git a/hilti/toolchain/include/ast/builder/expression.h b/hilti/toolchain/include/ast/builder/expression.h index 26803a2c6..e00c6f97c 100644 --- a/hilti/toolchain/include/ast/builder/expression.h +++ b/hilti/toolchain/include/ast/builder/expression.h @@ -348,5 +348,10 @@ inline auto port(Expression port, Expression protocol, const Meta& m = Meta()) { std::vector{std::move(port), std::move(protocol)}, m); } +inline Expression namedCtor(const std::string& name, const std::vector& args, Meta m = Meta()) { + return expression::UnresolvedOperator(operator_::Kind::Call, + {expression::Member(ID(name)), expression::Ctor(hilti::ctor::Tuple(args))}, + std::move(m)); +} } // namespace hilti::builder diff --git a/hilti/toolchain/include/ast/operators/common.h b/hilti/toolchain/include/ast/operators/common.h index afa6bf4af..27cdd99e0 100644 --- a/hilti/toolchain/include/ast/operators/common.h +++ b/hilti/toolchain/include/ast/operators/common.h @@ -279,6 +279,43 @@ private: \ __END_OPERATOR_CUSTOM +/** Defines a constructor-style call operator introduced by a keyword. */ +#define BEGIN_KEYWORD_CTOR(ns, cls, kw, result_, doc_) \ + __BEGIN_OPERATOR_CUSTOM(ns, Call, cls) \ + \ + const auto& signature() const { \ + static hilti::operator_::Signature _signature = {.result = result_, .args = parameters(), .doc = doc_}; \ + return _signature; \ + } \ + \ + const std::vector& operands() const { \ + static std::vector _operands = {{{}, hilti::type::Member(kw)}, \ + {{}, hilti::type::OperandList(signature().args)}}; \ + return _operands; \ + } \ + \ + std::string doc() const { return signature().doc; } \ + \ + hilti::Type result(const hilti::node::Range& ops) const { \ + return *hilti::operator_::type(signature().result, ops, ops); \ + } \ + \ + bool isLhs() const { return signature().lhs; } \ + hilti::operator_::Priority priority() const { return signature().priority; } \ + \ + void validate(const hilti::expression::ResolvedOperator& /* i */, hilti::operator_::position_t /* p */) const {} + + +#define END_KEYWORD_CTOR __END_OPERATOR_CUSTOM + +/** Shortcut to define a constructor-style call operator introduced by a keyword using a single argument. */ +#define STANDARD_KEYWORD_CTOR(ns, cls, kw, result_, ty_op, doc_) \ + BEGIN_KEYWORD_CTOR(ns, cls, kw, result_, doc_) \ + \ + std::vector parameters() const { return {{"op", ty_op}}; } \ + \ + END_KEYWORD_CTOR + /** * No-op to have the auto-generated code pick up on an operator that's * fully defined separately. diff --git a/hilti/toolchain/include/ast/operators/error.h b/hilti/toolchain/include/ast/operators/error.h index fc0acd536..56570e7c9 100644 --- a/hilti/toolchain/include/ast/operators/error.h +++ b/hilti/toolchain/include/ast/operators/error.h @@ -7,6 +7,8 @@ namespace hilti::operator_ { // NOLINT(modernize-concat-nested-namespaces) +STANDARD_KEYWORD_CTOR(error, Ctor, "error", type::Error(), type::String(), "Creates an error with the given message."); + BEGIN_METHOD(error, Description) const auto& signature() const { static auto _signature = Signature{.self = type::Error(), diff --git a/hilti/toolchain/include/ast/operators/interval.h b/hilti/toolchain/include/ast/operators/interval.h index c4e815fdd..3be88f164 100644 --- a/hilti/toolchain/include/ast/operators/interval.h +++ b/hilti/toolchain/include/ast/operators/interval.h @@ -27,6 +27,21 @@ STANDARD_OPERATOR_2x(interval, MultipleUnsignedInteger, Multiple, type::Interval STANDARD_OPERATOR_2x(interval, MultipleReal, Multiple, type::Interval(), type::Interval(), type::Real(), "Multiplies the interval with the given factor."); +STANDARD_KEYWORD_CTOR(interval, CtorSignedIntegerNs, "interval_ns", type::Interval(), + type::SignedInteger(type::Wildcard()), + "Creates an interval interpreting the argument as number of nanoseconds."); +STANDARD_KEYWORD_CTOR(interval, CtorSignedIntegerSecs, "interval", type::Interval(), + type::SignedInteger(type::Wildcard()), + "Creates an interval interpreting the argument as number of seconds."); +STANDARD_KEYWORD_CTOR(interval, CtorUnsignedIntegerNs, "interval_ns", type::Interval(), + type::UnsignedInteger(type::Wildcard()), + "Creates an interval interpreting the argument as number of nanoseconds."); +STANDARD_KEYWORD_CTOR(interval, CtorUnsignedIntegerSecs, "interval", type::Interval(), + type::UnsignedInteger(type::Wildcard()), + "Creates an interval interpreting the argument as number of seconds."); +STANDARD_KEYWORD_CTOR(interval, CtorRealSecs, "interval", type::Interval(), type::Real(), + "Creates an interval interpreting the argument as number of seconds."); + BEGIN_METHOD(interval, Seconds) const auto& signature() const { static auto _signature = diff --git a/hilti/toolchain/include/ast/operators/port.h b/hilti/toolchain/include/ast/operators/port.h index ad8dbe102..c1651f097 100644 --- a/hilti/toolchain/include/ast/operators/port.h +++ b/hilti/toolchain/include/ast/operators/port.h @@ -2,8 +2,12 @@ #pragma once +#include + #include #include +#include +#include #include namespace hilti::operator_ { @@ -11,6 +15,12 @@ namespace hilti::operator_ { STANDARD_OPERATOR_2(port, Equal, type::Bool(), type::Port(), type::Port(), "Compares two port values.") STANDARD_OPERATOR_2(port, Unequal, type::Bool(), type::Port(), type::Port(), "Compares two port values.") +BEGIN_KEYWORD_CTOR(port, Ctor, "port", type::Port(), "Creates a port instance.") + std::vector parameters() const { + return {{"port", hilti::type::UnsignedInteger(16)}, {"protocol", type::Enum(type::Wildcard())}}; + } +END_KEYWORD_CTOR + BEGIN_METHOD(port, Protocol) const auto& signature() const { static auto _signature = Signature{.self = type::Port(), diff --git a/hilti/toolchain/include/ast/operators/signed-integer.h b/hilti/toolchain/include/ast/operators/signed-integer.h index a08bf17ee..a5230f660 100644 --- a/hilti/toolchain/include/ast/operators/signed-integer.h +++ b/hilti/toolchain/include/ast/operators/signed-integer.h @@ -114,4 +114,21 @@ STANDARD_OPERATOR_2x(signed_integer, CastToInterval, Cast, type::Interval(), typ STANDARD_OPERATOR_2x(signed_integer, CastToBool, Cast, type::Bool(), type::SignedInteger(type::Wildcard()), type::Type_(type::Bool()), "Converts the value to a boolean by comparing against zero"); +STANDARD_KEYWORD_CTOR(signed_integer, CtorSigned8, "int8", type::SignedInteger(8), + type::SignedInteger(type::Wildcard()), "Creates a 8-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorSigned16, "int16", type::SignedInteger(16), + type::SignedInteger(type::Wildcard()), "Creates a 16-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorSigned32, "int32", type::SignedInteger(32), + type::SignedInteger(type::Wildcard()), "Creates a 32-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorSigned64, "int64", type::SignedInteger(64), + type::SignedInteger(type::Wildcard()), "Creates a 64-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorUnsigned8, "int8", type::SignedInteger(8), + type::UnsignedInteger(type::Wildcard()), "Creates a 8-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorUnsigned16, "int16", type::SignedInteger(16), + type::UnsignedInteger(type::Wildcard()), "Creates a 16-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorUnsigned32, "int32", type::SignedInteger(32), + type::UnsignedInteger(type::Wildcard()), "Creates a 32-bit signed integer value."); +STANDARD_KEYWORD_CTOR(signed_integer, CtorUnsigned64, "int64", type::SignedInteger(64), + type::UnsignedInteger(type::Wildcard()), "Creates a 64-bit signed integer value."); + } // namespace hilti::operator_ diff --git a/hilti/toolchain/include/ast/operators/stream.h b/hilti/toolchain/include/ast/operators/stream.h index 8f764b5aa..4e0e517cb 100644 --- a/hilti/toolchain/include/ast/operators/stream.h +++ b/hilti/toolchain/include/ast/operators/stream.h @@ -55,6 +55,9 @@ STANDARD_OPERATOR_2(stream::iterator, Sum, type::stream::Iterator(), type::const STANDARD_OPERATOR_2(stream::iterator, SumAssign, type::stream::Iterator(), type::stream::Iterator(), type::UnsignedInteger(64), "Advances the iterator by the given number of stream.") +STANDARD_KEYWORD_CTOR(stream, Ctor, "stream", type::Stream(), type::constant(type::Bytes()), + "Creates a stream instance preinitialized with the given data."); + BEGIN_METHOD(stream::iterator, Offset) const auto& signature() const { static auto _signature = Signature{.self = type::constant(type::stream::Iterator()), diff --git a/hilti/toolchain/include/ast/operators/time.h b/hilti/toolchain/include/ast/operators/time.h index ebf27c1c6..036a8b387 100644 --- a/hilti/toolchain/include/ast/operators/time.h +++ b/hilti/toolchain/include/ast/operators/time.h @@ -26,6 +26,17 @@ STANDARD_OPERATOR_2(time, GreaterEqual, type::Bool(), type::Time(), type::Time() STANDARD_OPERATOR_2(time, Lower, type::Bool(), type::Time(), type::Time(), "Compares the times."); STANDARD_OPERATOR_2(time, LowerEqual, type::Bool(), type::Time(), type::Time(), "Compares the times."); +STANDARD_KEYWORD_CTOR(time, CtorSignedIntegerNs, "time_ns", type::Time(), type::SignedInteger(type::Wildcard()), + "Creates an time interpreting the argument as number of nanoseconds."); +STANDARD_KEYWORD_CTOR(time, CtorSignedIntegerSecs, "time", type::Time(), type::SignedInteger(type::Wildcard()), + "Creates an time interpreting the argument as number of seconds."); +STANDARD_KEYWORD_CTOR(time, CtorUnsignedIntegerNs, "time_ns", type::Time(), type::UnsignedInteger(type::Wildcard()), + "Creates an time interpreting the argument as number of nanoseconds."); +STANDARD_KEYWORD_CTOR(time, CtorUnsignedIntegerSecs, "time", type::Time(), type::UnsignedInteger(type::Wildcard()), + "Creates an time interpreting the argument as number of seconds."); +STANDARD_KEYWORD_CTOR(time, CtorRealSecs, "time", type::Time(), type::Real(), + "Creates an time interpreting the argument as number of seconds."); + BEGIN_METHOD(time, Seconds) const auto& signature() const { static auto _signature = diff --git a/hilti/toolchain/include/ast/operators/unsigned-integer.h b/hilti/toolchain/include/ast/operators/unsigned-integer.h index f4067bb4f..b37f8d987 100644 --- a/hilti/toolchain/include/ast/operators/unsigned-integer.h +++ b/hilti/toolchain/include/ast/operators/unsigned-integer.h @@ -48,6 +48,20 @@ inline static auto widestTypeUnsigned() { return type::UnsignedInteger(std::max(w1, w2)); }; } + +inline static auto sameWidthSigned() { + return [=](const hilti::node::Range& orig_ops, + const hilti::node::Range& resolved_ops) -> std::optional { + if ( orig_ops.empty() && resolved_ops.empty() ) + return type::DocOnly("int<*>"); + + if ( auto t = orig_ops[0].type().tryAs() ) + return type::SignedInteger(t->width()); + else + return {}; + }; +} + } // namespace detail STANDARD_OPERATOR_1(unsigned_integer, DecrPostfix, operator_::sameTypeAs(0, "uint"), @@ -58,6 +72,8 @@ STANDARD_OPERATOR_1(unsigned_integer, IncrPostfix, operator_::sameTypeAs(0, "uin type::UnsignedInteger(type::Wildcard()), "Increments the value, returning the old value."); STANDARD_OPERATOR_1(unsigned_integer, IncrPrefix, operator_::sameTypeAs(0, "uint"), type::UnsignedInteger(type::Wildcard()), "Increments the value, returning the new value."); +STANDARD_OPERATOR_1(unsigned_integer, SignNeg, detail::sameWidthSigned(), type::UnsignedInteger(type::Wildcard()), + "Inverts the sign of the integer."); STANDARD_OPERATOR_1(unsigned_integer, Negate, operator_::sameTypeAs(0, "uint"), type::UnsignedInteger(type::Wildcard()), "Computes the bit-wise negation of the integer."); STANDARD_OPERATOR_2(unsigned_integer, BitAnd, detail::widestTypeUnsigned(), detail::widestTypeUnsigned(), @@ -127,4 +143,22 @@ STANDARD_OPERATOR_2x(unsigned_integer, CastToInterval, Cast, type::Interval(), t type::Type_(type::Interval()), "Interprets the value as number of seconds."); STANDARD_OPERATOR_2x(unsigned_integer, CastToBool, Cast, type::Bool(), type::SignedInteger(type::Wildcard()), type::Type_(type::Bool()), "Converts the value to a boolean by comparing against zero"); + +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorSigned8, "uint8", type::UnsignedInteger(8), + type::SignedInteger(type::Wildcard()), "Creates a 8-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorSigned16, "uint16", type::UnsignedInteger(16), + type::SignedInteger(type::Wildcard()), "Creates a 16-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorSigned32, "uint32", type::UnsignedInteger(32), + type::SignedInteger(type::Wildcard()), "Creates a 32-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorSigned64, "uint64", type::UnsignedInteger(64), + type::SignedInteger(type::Wildcard()), "Creates a 64-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorUnsigned8, "uint8", type::UnsignedInteger(8), + type::UnsignedInteger(type::Wildcard()), "Creates a 8-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorUnsigned16, "uint16", type::UnsignedInteger(16), + type::UnsignedInteger(type::Wildcard()), "Creates a 16-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorUnsigned32, "uint32", type::UnsignedInteger(32), + type::UnsignedInteger(type::Wildcard()), "Creates a 32-bit unsigned integer value."); +STANDARD_KEYWORD_CTOR(unsigned_integer, CtorUnsigned64, "uint64", type::UnsignedInteger(64), + type::UnsignedInteger(type::Wildcard()), "Creates a 64-bit unsigned integer value."); + } // namespace hilti::operator_ diff --git a/hilti/toolchain/include/compiler/detail/visitors.h b/hilti/toolchain/include/compiler/detail/visitors.h index 2a5d1716b..6cf631302 100644 --- a/hilti/toolchain/include/compiler/detail/visitors.h +++ b/hilti/toolchain/include/compiler/detail/visitors.h @@ -58,6 +58,15 @@ std::string renderOperatorInstance(const expression::ResolvedOperator& o); void renderNode(const Node& n, std::ostream& out, bool include_scopes = false); void renderNode(const Node& n, logging::DebugStream stream, bool include_scopes = false); +/** + * Folds an expression into a constant value if that's possible. Note that the + * current implementation is very, very basic, and covers just a few cases. If + * the function returns an error, that does not necessarily mean that the + * expression is not represeneting a constant value, but only that we aren't + * able to compute it. + */ +Result> foldConstant(const Node& expr); + namespace ast { /** Implements the corresponding functionality for the default HILTI compiler plugin. */ void buildScopes(const std::shared_ptr& ctx, Node* root, Unit* unit); diff --git a/hilti/toolchain/include/compiler/printer.h b/hilti/toolchain/include/compiler/printer.h index 0e8bee622..57de4275a 100644 --- a/hilti/toolchain/include/compiler/printer.h +++ b/hilti/toolchain/include/compiler/printer.h @@ -38,10 +38,6 @@ class Stream { char newline() const { return _nl; } - const ID& currentScope() const { return _scopes.back(); } - void pushScope(ID id) { _scopes.push_back(std::move(id)); } - void popScope() { _scopes.pop_back(); } - bool isCompact() { return _compact; } bool setCompact(bool new_compact) { auto old = _compact; @@ -120,7 +116,6 @@ class Stream { bool _first_in_block = false; bool _last_in_block = false; bool _expand_subsequent_type = false; - std::vector _scopes = {""}; }; } // namespace hilti::printer diff --git a/hilti/toolchain/src/compiler/codegen/operators.cc b/hilti/toolchain/src/compiler/codegen/operators.cc index 5e2865375..9ba32adbb 100644 --- a/hilti/toolchain/src/compiler/codegen/operators.cc +++ b/hilti/toolchain/src/compiler/codegen/operators.cc @@ -274,7 +274,15 @@ struct Visitor : hilti::visitor::PreOrder { return fmt("::hilti::rt::enum_::has_label(%s, %s)", op0(n), cg->typeInfo(n.op0().type())); } + // Error + + result_t operator()(const operator_::error::Ctor& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::result::Error(%s)", args[0]); + } + // Exception + result_t operator()(const operator_::exception::Ctor& n) { std::string type; @@ -305,6 +313,31 @@ struct Visitor : hilti::visitor::PreOrder { result_t operator()(const operator_::interval::Sum& n) { return binary(n, "+"); } result_t operator()(const operator_::interval::Unequal& n) { return binary(n, "!="); } + result_t operator()(const operator_::interval::CtorSignedIntegerSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Interval(%s, hilti::rt::Interval::SecondTag())", args[0]); + } + + result_t operator()(const operator_::interval::CtorSignedIntegerNs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Interval(%s, hilti::rt::Interval::NanosecondTag())", args[0]); + } + + result_t operator()(const operator_::interval::CtorUnsignedIntegerSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Interval(%s, hilti::rt::Interval::SecondTag())", args[0]); + } + + result_t operator()(const operator_::interval::CtorUnsignedIntegerNs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Interval(%s, hilti::rt::Interval::NanosecondTag())", args[0]); + } + + result_t operator()(const operator_::interval::CtorRealSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Interval(%f, hilti::rt::Interval::SecondTag())", args[0]); + } + // List result_t operator()(const operator_::list::iterator::IncrPostfix& n) { return fmt("%s++", op0(n)); } result_t operator()(const operator_::list::iterator::IncrPrefix& n) { return fmt("++%s", op0(n)); } @@ -371,7 +404,7 @@ struct Visitor : hilti::visitor::PreOrder { /// Real result_t operator()(const operator_::real::CastToInterval& n) { - return fmt("::hilti::rt::Interval(%f, hilti::rt::Interval::NanosecondTag())", op0(n)); + return fmt("::hilti::rt::Interval(%f, hilti::rt::Interval::SecondTag())", op0(n)); } result_t operator()(const operator_::real::CastToTime& n) { return fmt("::hilti::rt::Time(%f, hilti::rt::Time::SecondTag())", op0(n)); @@ -502,6 +535,12 @@ struct Visitor : hilti::visitor::PreOrder { result_t operator()(const operator_::port::Equal& n) { return binary(n, "=="); } result_t operator()(const operator_::port::Unequal& n) { return binary(n, "!="); } + + result_t operator()(const operator_::port::Ctor& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Port(%s, %s)", args[0], args[1]); + } + result_t operator()(const operator_::port::Protocol& n) { return fmt("%s.protocol()", op0(n)); } // Set @@ -626,6 +665,11 @@ struct Visitor : hilti::visitor::PreOrder { result_t operator()(const operator_::stream::SumAssignView& n) { return fmt("%s.append(%s)", op0(n), op1(n)); } result_t operator()(const operator_::stream::SumAssignBytes& n) { return fmt("%s.append(%s)", op0(n), op1(n)); } + result_t operator()(const operator_::stream::Ctor& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Stream(%s)", args[0]); + } + result_t operator()(const operator_::stream::Freeze& n) { auto [self, args] = methodArguments(n); return fmt("%s.freeze()", self); @@ -849,6 +893,46 @@ struct Visitor : hilti::visitor::PreOrder { return fmt("static_cast<%s>(%s)", cg->compile(t, codegen::TypeUsage::Storage), op0(n)); } + result_t operator()(const operator_::signed_integer::CtorSigned8& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorSigned16& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorSigned32& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorSigned64& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned8& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned16& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned32& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned64& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + // Time result_t operator()(const operator_::time::DifferenceInterval& n) { return binary(n, "-"); } @@ -863,6 +947,31 @@ struct Visitor : hilti::visitor::PreOrder { result_t operator()(const operator_::time::SumInterval& n) { return binary(n, "+"); } result_t operator()(const operator_::time::Unequal& n) { return binary(n, "!="); } + result_t operator()(const operator_::time::CtorSignedIntegerSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Time(%s, hilti::rt::Time::SecondTag())", args[0]); + } + + result_t operator()(const operator_::time::CtorSignedIntegerNs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Time(%s, hilti::rt::Time::NanosecondTag())", args[0]); + } + + result_t operator()(const operator_::time::CtorUnsignedIntegerSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Time(%s, hilti::rt::Time::SecondTag())", args[0]); + } + + result_t operator()(const operator_::time::CtorUnsignedIntegerNs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Time(%s, hilti::rt::Time::NanosecondTag())", args[0]); + } + + result_t operator()(const operator_::time::CtorRealSecs& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("::hilti::rt::Time(%f, hilti::rt::Time::SecondTag())", args[0]); + } + // Tuple result_t operator()(const operator_::tuple::CustomAssign& n) { @@ -936,6 +1045,7 @@ struct Visitor : hilti::visitor::PreOrder { } result_t operator()(const operator_::unsigned_integer::ShiftLeft& n) { return fmt("(%s << %s)", op0(n), op1(n)); } result_t operator()(const operator_::unsigned_integer::ShiftRight& n) { return fmt("(%s >> %s)", op0(n), op1(n)); } + result_t operator()(const operator_::unsigned_integer::SignNeg& n) { return fmt("(-%s)", op0(n)); } result_t operator()(const operator_::unsigned_integer::Sum& n) { return fmt("%s + %s", op0(n), op1(n)); } result_t operator()(const operator_::unsigned_integer::SumAssign& n) { return fmt("%s += %s", op0(n), op1(n)); } result_t operator()(const operator_::unsigned_integer::Unequal& n) { return fmt("%s != %s", op0(n), op1(n)); } @@ -955,6 +1065,46 @@ struct Visitor : hilti::visitor::PreOrder { return fmt("static_cast<%s>(%s)", cg->compile(t, codegen::TypeUsage::Storage), op0(n)); } + result_t operator()(const operator_::unsigned_integer::CtorSigned8& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned16& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned32& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned64& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned8& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned16& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned32& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned64& n) { + auto args = tupleArguments(n, n.op1()); + return fmt("static_cast(%s)", args[0]); + } + // Vector result_t operator()(const operator_::vector::iterator::IncrPostfix& n) { return fmt("%s++", op0(n)); } result_t operator()(const operator_::vector::iterator::IncrPrefix& n) { return fmt("++%s", op0(n)); } diff --git a/hilti/toolchain/src/compiler/codegen/unpack.cc b/hilti/toolchain/src/compiler/codegen/unpack.cc index f78df22f6..97466f714 100644 --- a/hilti/toolchain/src/compiler/codegen/unpack.cc +++ b/hilti/toolchain/src/compiler/codegen/unpack.cc @@ -31,6 +31,8 @@ struct Visitor : hilti::visitor::PreOrder { case Kind::Pack: return "pack"; case Kind::Unpack: return "unpack"; } + + util::cannot_be_reached(); } result_t operator()(const type::Address& n) { @@ -38,6 +40,8 @@ struct Visitor : hilti::visitor::PreOrder { case Kind::Pack: return fmt("::hilti::rt::address::pack(%s, %s)", data, args[0]); case Kind::Unpack: return fmt("::hilti::rt::address::unpack(%s, %s, %s)", data, args[0], args[1]); } + + util::cannot_be_reached(); } result_t operator()(const type::UnsignedInteger& n) { diff --git a/hilti/toolchain/src/compiler/parser/parser.yy b/hilti/toolchain/src/compiler/parser/parser.yy index 883c0d9d6..edfbef530 100644 --- a/hilti/toolchain/src/compiler/parser/parser.yy +++ b/hilti/toolchain/src/compiler/parser/parser.yy @@ -33,8 +33,8 @@ namespace hilti { namespace detail { class Parser; } } %verbose %glr-parser -%expect 115 -%expect-rr 189 +%expect 113 +%expect-rr 205 %{ @@ -65,26 +65,6 @@ static hilti::Type viewForType(hilti::Type t, hilti::Meta m) { } } - -/** - * Checks if an unsigned integer value can be represented as an int64_t. - * - * @param x value to check - * @param positive if false, check if ``-x`` can be represented instead of ``x`` itself. - * @param m location information to associate with error message. - * @return *x* on success, or zero on failure as a temporary stand-in; in the - * latter cases an error is reported, too - */ -static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& m) { - uint64_t max = (positive ? std::numeric_limits::max() : std::fabs(std::numeric_limits::min())); - - if ( x <= max ) - return x; - - hilti::logger().error("signed integer value out of range", m.location()); - return 0; // Return dummy value -} - #define __loc__ toMeta(yylhs.location) %} @@ -164,7 +144,12 @@ static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& %token INIT "init" %token INOUT "inout" %token INT "int" +%token INT16 "int16" +%token INT32 "int32" +%token INT64 "int64" +%token INT8 "int8" %token INTERVAL "interval" +%token INTERVAL_NS "interval_ns" %token IOSRC "iosrc" %token ITERATOR "iterator" %token CONST_ITERATOR "const_iterator" @@ -208,6 +193,7 @@ static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& %token STRUCT "struct" %token SWITCH "switch" %token TIME "time" +%token TIME_NS "time_ns" %token TIMER "timer" %token TIMERMGR "timer_mgr" %token TIMESASSIGN "*=" @@ -218,6 +204,10 @@ static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& %token TYPE "type" %token TYPEINFO "typeinfo" %token UINT "uint" +%token UINT16 "uint16" +%token UINT32 "uint32" +%token UINT64 "uint64" +%token UINT8 "uint8" %token UNION "union" %token UNPACK "unpack" %token UNSET "unset" @@ -235,7 +225,7 @@ static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& %type > struct_fields union_fields opt_union_fields %type base_type_no_attrs base_type type function_type tuple_type struct_type enum_type union_type %type ctor tuple struct_ list regexp map set -%type expr tuple_elem tuple_expr member_expr expr_0 expr_1 expr_2 expr_3 expr_4 expr_5 expr_6 expr_7 expr_8 expr_9 expr_a expr_b expr_c expr_d expr_e expr_f expr_g +%type expr tuple_elem tuple_expr member_expr ctor_expr expr_0 expr_1 expr_2 expr_3 expr_4 expr_5 expr_6 expr_7 expr_8 expr_9 expr_a expr_b expr_c expr_d expr_e expr_f expr_g %type > opt_tuple_elems1 opt_tuple_elems2 exprs opt_exprs opt_type_arguments %type > opt_func_default_expr %type function_with_body method_with_body hook_with_body function_without_body @@ -269,10 +259,6 @@ static uint64_t check_int64_range(uint64_t x, bool positive, const hilti::Meta& %type , std::vector>> global_scope_items -%type const_real -%type const_sint -%type const_uint - %% %start module; @@ -787,8 +773,8 @@ expr_e : BEGIN_ '(' expr ')' { $$ = hilti::expression::Unres | expr_f { $$ = std::move($1); } expr_f : ctor { $$ = hilti::expression::Ctor(std::move($1), __loc__); } - | PORT '(' expr ',' expr ')' { $$ = hilti::builder::port(std::move($3), std::move($5), __loc__); } - | '-' expr_g { $$ = hilti::expression::UnresolvedOperator(hilti::operator_::Kind::SignNeg, {std::move($2)}, __loc__); } + | ctor_expr { $$ = std::move($1); } + | '-' expr_f { $$ = hilti::expression::UnresolvedOperator(hilti::operator_::Kind::SignNeg, {std::move($2)}, __loc__); } | '[' expr FOR local_id IN expr ']' { $$ = hilti::expression::ListComprehension(std::move($6), std::move($2), std::move($4), {}, __loc__); } | '[' expr FOR local_id IN expr IF expr ']' @@ -807,41 +793,26 @@ member_expr : local_id { $$ = hilti::expression::Membe ctor : CBOOL { $$ = hilti::ctor::Bool($1, __loc__); } | CBYTES { $$ = hilti::ctor::Bytes(std::move($1), __loc__); } | CSTRING { $$ = hilti::ctor::String($1, __loc__); } - | const_real { $$ = hilti::ctor::Real($1, __loc__); } | CUINTEGER { $$ = hilti::ctor::UnsignedInteger($1, 64, __loc__); } - | '+' CUINTEGER { $$ = hilti::ctor::SignedInteger(check_int64_range($2, true, __loc__), 64, __loc__); } - | '-' CUINTEGER { $$ = hilti::ctor::SignedInteger(-check_int64_range($2, false, __loc__), 64, __loc__); } + | '+' CUINTEGER { if ( $2 > static_cast(std::numeric_limits::max()) ) + logger().error("integer constant out of range", __loc__.location()); + + $$ = hilti::ctor::SignedInteger($2, 64, __loc__); + } + | CUREAL { $$ = hilti::ctor::Real($1, __loc__); } + | '+' CUREAL { $$ = hilti::ctor::Real($2, __loc__);; } | CNULL { $$ = hilti::ctor::Null(__loc__); } | CADDRESS { $$ = hilti::ctor::Address(hilti::ctor::Address::Value($1), __loc__); } | CADDRESS '/' CUINTEGER { $$ = hilti::ctor::Network(hilti::ctor::Network::Value($1, $3), __loc__); } | CPORT { $$ = hilti::ctor::Port(hilti::ctor::Port::Value($1), __loc__); } - | INTERVAL '(' const_real ')' { try { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value($3, hilti::rt::Interval::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value()); error(@$, e.what()); } - } - | INTERVAL '(' const_sint ')' { try { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value($3, hilti::rt::Interval::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value()); error(@$, e.what()); } - } - | TIME '(' const_real ')' { try { $$ = hilti::ctor::Time(hilti::ctor::Time::Value($3, hilti::rt::Time::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Time(hilti::ctor::Time::Value()); error(@$, e.what()); } - } - | TIME '(' const_uint ')' { try { $$ = hilti::ctor::Time(hilti::ctor::Time::Value($3, hilti::rt::Time::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Time(hilti::ctor::Time::Value()); error(@$, e.what()); } - } - | STREAM '(' CBYTES ')' { $$ = hilti::ctor::Stream(std::move($3), __loc__); } - | ERROR '(' CSTRING ')' { $$ = hilti::ctor::Error(std::move($3), __loc__); } + /* There are more here that we could move into ctor_expr and have them use namedCtor. + But not sure if that'd change much so leaving here for now. + */ | OPTIONAL '(' expr ')' { $$ = hilti::ctor::Optional(std::move($3), __loc__); } | DEFAULT type_param_begin type type_param_end '(' opt_exprs ')' { $$ = hilti::ctor::Default(std::move($3), std::move($6), __loc__); } - - | UINT '<' CUINTEGER '>' '(' CUINTEGER ')' - { $$ = hilti::ctor::UnsignedInteger($6, $3, __loc__); } - | INT '<' CUINTEGER '>' '(' CUINTEGER ')' - { $$ = hilti::ctor::SignedInteger(check_int64_range($6, true, __loc__), $3, __loc__); } - | INT '<' CUINTEGER '>' '(' '-' CUINTEGER ')' - { $$ = hilti::ctor::SignedInteger(-check_int64_range($7, false, __loc__), $3, __loc__); } - | list { $$ = std::move($1); } | map { $$ = std::move($1); } | regexp { $$ = std::move($1); } @@ -850,17 +821,22 @@ ctor : CBOOL { $$ = hilti::ctor::Bool($1, __ | tuple { $$ = std::move($1); } ; -const_real : CUREAL { $$ = $1; } - | '+' CUREAL { $$ = $2; } - | '-' CUREAL { $$ = -$2; } - -const_sint : CUINTEGER { $$ = check_int64_range($1, true, __loc__); } - | '+' CUINTEGER { $$ = check_int64_range($2, true, __loc__); } - | '-' CUINTEGER { $$ = -check_int64_range($2, false, __loc__); } - -const_uint : CUINTEGER { $$ = $1; } - | '+' CUINTEGER { $$ = $2; } - +ctor_expr : INTERVAL '(' expr ')' { $$ = hilti::builder::namedCtor("interval", { std::move($3) }, __loc__); } + | INTERVAL_NS '(' expr ')' { $$ = hilti::builder::namedCtor("interval_ns", { std::move($3) }, __loc__); } + | TIME '(' expr ')' { $$ = hilti::builder::namedCtor("time", { std::move($3) }, __loc__); } + | TIME_NS '(' expr ')' { $$ = hilti::builder::namedCtor("time_ns", { std::move($3) }, __loc__); } + | STREAM '(' expr ')' { $$ = hilti::builder::namedCtor("stream", { std::move($3) }, __loc__); } + | ERROR '(' expr ')' { $$ = hilti::builder::namedCtor("error", { std::move($3) }, __loc__); } + | INT8 '(' expr ')' { $$ = hilti::builder::namedCtor("int8", { std::move($3) }, __loc__); } + | INT16 '(' expr ')' { $$ = hilti::builder::namedCtor("int16", { std::move($3) }, __loc__); } + | INT32 '(' expr ')' { $$ = hilti::builder::namedCtor("int32", { std::move($3) }, __loc__); } + | INT64 '(' expr ')' { $$ = hilti::builder::namedCtor("int64", { std::move($3) }, __loc__); } + | UINT8 '(' expr ')' { $$ = hilti::builder::namedCtor("uint8", { std::move($3) }, __loc__); } + | UINT16 '(' expr ')' { $$ = hilti::builder::namedCtor("uint16", { std::move($3) }, __loc__); } + | UINT32 '(' expr ')' { $$ = hilti::builder::namedCtor("uint32", { std::move($3) }, __loc__); } + | UINT64 '(' expr ')' { $$ = hilti::builder::namedCtor("uint64", { std::move($3) }, __loc__); } + | PORT '(' expr ',' expr ')' { $$ = hilti::builder::namedCtor("port", {std::move($3), std::move($5)}, __loc__); } + ; tuple : '(' opt_tuple_elems1 ')' { $$ = hilti::ctor::Tuple(std::move($2), __loc__); } diff --git a/hilti/toolchain/src/compiler/parser/scanner.ll b/hilti/toolchain/src/compiler/parser/scanner.ll index 575754eb8..205068a7c 100644 --- a/hilti/toolchain/src/compiler/parser/scanner.ll +++ b/hilti/toolchain/src/compiler/parser/scanner.ll @@ -112,11 +112,16 @@ hook return token::HOOK; if return token::IF; import return token::IMPORT; in return token::IN; +int16 return token::INT16; +int32 return token::INT32; +int64 return token::INT64; +int8 return token::INT8; !in return token::NOT_IN; init return token::INIT; inout return token::INOUT; int return token::INT; interval return token::INTERVAL; +interval_ns return token::INTERVAL_NS; iterator return token::ITERATOR; list return token::LIST; local return token::LOCAL; @@ -144,11 +149,16 @@ struct return token::STRUCT; switch return token::SWITCH; throw return token::THROW; time return token::TIME; +time_ns return token::TIME_NS; try return token::TRY; tuple return token::TUPLE; type return token::TYPE; typeinfo return token::TYPEINFO; uint return token::UINT; +uint16 return token::UINT16; +uint32 return token::UINT32; +uint64 return token::UINT64; +uint8 return token::UINT8; union return token::UNION; unpack return token::UNPACK; unset return token::UNSET; diff --git a/hilti/toolchain/src/compiler/visitors/constant-folder.cc b/hilti/toolchain/src/compiler/visitors/constant-folder.cc new file mode 100644 index 000000000..c812c376c --- /dev/null +++ b/hilti/toolchain/src/compiler/visitors/constant-folder.cc @@ -0,0 +1,357 @@ +// Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details. + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace hilti; + +namespace { + +// Internal version of _foldConstant() that passes expceptions through to caller. +static Result _foldConstant(const Node& expr); + +template +Result foldConstant(const Expression& expr) { + auto ctor = _foldConstant(expr); + if ( ! ctor ) + return ctor.error(); + + if ( auto ctor_ = ctor->tryAs() ) + return *ctor_; + else + return result::Error("unexpected type"); +} + +// For now, this is only a very basic constant folder that only covers cases we +// need to turn type constructor expressions coming with a single argument into +// ctor expressions. +struct VisitorConstantFolder : public visitor::PreOrder, VisitorConstantFolder> { + // Helper to replace an type constructor expression that receives a + // constant argument with a corresponding ctor expression. + template + result_t tryReplaceCtorExpression(const Operator& op, position_t p, Fn cb) { + if ( auto ctor = foldConstant(callArgument(op, 0)) ) { + auto x = cb(*ctor); + x.setMeta(p.node.meta()); + return {std::move(x)}; + } + else + return std::nullopt; + } + + // Helper to extract the 1st argument of a call expression. + Expression callArgument(const expression::ResolvedOperatorBase& o, int i) { + auto ctor = o.op1().as().ctor(); + + if ( auto x = ctor.tryAs() ) + ctor = x->coercedCtor(); + + return ctor.as().value()[i]; + } + + // Helper to cast an uint64 to int64, with range check. + int64_t to_int64(uint64_t x, position_t& p) { + try { + return SafeInt(x); + } catch ( ... ) { + throw hilti::rt::OutOfRange("integer value out of range"); + } + } + + // Helper to cast an int64 to uint64, with range check. + uint64_t to_uint64(int64_t x, position_t& p) { + if ( x < 0 ) + throw hilti::rt::OutOfRange("integer value out of range"); + + return static_cast(x); + } + + result_t operator()(const expression::Ctor& n, position_t p) { return n.ctor(); } + + result_t operator()(const operator_::signed_integer::SignNeg& n, position_t p) { + auto op = foldConstant(n.op0()); + if ( ! op ) + return std::nullopt; + + return ctor::SignedInteger(-op->value(), op->width(), p.node.meta()); + } + + result_t operator()(const expression::Grouping& n, position_t p) { + auto x = _foldConstant(n.expression()); + if ( ! x ) + return std::nullopt; + + return *x; + } + + result_t operator()(const expression::LogicalOr& n, position_t p) { + auto op0 = foldConstant(n.op0()); + auto op1 = foldConstant(n.op1()); + if ( ! (op0 && op1) ) + return std::nullopt; + + return ctor::Bool(op0->value() || op1->value(), p.node.meta()); + } + + result_t operator()(const expression::LogicalAnd& n, position_t p) { + auto op0 = foldConstant(n.op0()); + auto op1 = foldConstant(n.op1()); + if ( ! (op0 && op1) ) + return std::nullopt; + + return ctor::Bool(op0->value() && op1->value(), p.node.meta()); + } + + result_t operator()(const expression::LogicalNot& n, position_t p) { + auto op = foldConstant(n.expression()); + if ( ! op ) + return std::nullopt; + + return ctor::Bool(! op->value(), p.node.meta()); + } + + result_t operator()(const expression::ResolvedID& n, position_t p) { + // We cannot fold the optimizer's feature constants currently because + // that would mess up its state tracking. We continue to let the + // optimizer handle expressions involving these. + // + // TODO: Can we unify this? + if ( util::startsWith(n.id().sub(1), "__feat") ) + return std::nullopt; + + auto const_ = n.declaration().tryAs(); + if ( ! const_ ) + return std::nullopt; + + auto x = _foldConstant(const_->value()); + if ( ! x ) + return std::nullopt; + + return *x; + } + + result_t operator()(const operator_::unsigned_integer::SignNeg& n, position_t p) { + auto op = foldConstant(n.op0()); + if ( ! op ) + return std::nullopt; + + return ctor::SignedInteger(hilti::rt::integer::safe_negate(op->value()), op->width(), p.node.meta()); + } + + result_t operator()(const operator_::real::SignNeg& n, position_t p) { + auto op = foldConstant(n.op0()); + if ( ! op ) + return std::nullopt; + + return ctor::Real(-op->value(), p.node.meta()); + } + + result_t operator()(const operator_::error::Ctor& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { return ctor::Error(ctor.value()); }); + } + + result_t operator()(const operator_::interval::CtorSignedIntegerSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Interval(ctor::Interval::Value(ctor.value(), hilti::rt::Interval::SecondTag())); + }); + } + + result_t operator()(const operator_::interval::CtorUnsignedIntegerSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Interval(ctor::Interval::Value(ctor.value(), hilti::rt::Interval::SecondTag())); + }); + } + + result_t operator()(const operator_::interval::CtorSignedIntegerNs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Interval(ctor::Interval::Value(ctor.value(), hilti::rt::Interval::NanosecondTag())); + }); + } + + result_t operator()(const operator_::interval::CtorUnsignedIntegerNs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Interval(ctor::Interval::Value(ctor.value(), hilti::rt::Interval::NanosecondTag())); + }); + } + + result_t operator()(const operator_::interval::CtorRealSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Interval(ctor::Interval::Value(ctor.value(), hilti::rt::Interval::SecondTag())); + }); + } + + result_t operator()(const operator_::port::Ctor& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Port(ctor::Port::Value(ctor.value())); + }); + } + + result_t operator()(const operator_::signed_integer::CtorSigned8& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::SignedInteger(ctor.value(), 8); + }); + } + + result_t operator()(const operator_::signed_integer::CtorSigned16& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::SignedInteger(ctor.value(), 16); + }); + } + + result_t operator()(const operator_::signed_integer::CtorSigned32& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::SignedInteger(ctor.value(), 32); + }); + } + + result_t operator()(const operator_::signed_integer::CtorSigned64& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::SignedInteger(ctor.value(), 64); + }); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned8& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::SignedInteger(to_int64(ctor.value(), p), 8); + }); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned16& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::SignedInteger(to_int64(ctor.value(), p), 16); + }); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned32& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::SignedInteger(to_int64(ctor.value(), p), 32); + }); + } + + result_t operator()(const operator_::signed_integer::CtorUnsigned64& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::SignedInteger(to_int64(ctor.value(), p), 64); + }); + } + + result_t operator()(const operator_::time::CtorSignedIntegerSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Time(ctor::Time::Value(ctor.value(), hilti::rt::Time::SecondTag())); + }); + } + + result_t operator()(const operator_::time::CtorUnsignedIntegerSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Time(ctor::Time::Value(ctor.value(), hilti::rt::Time::SecondTag())); + }); + } + + result_t operator()(const operator_::stream::Ctor& op, position_t p) { + return tryReplaceCtorExpression(op, p, + [](const auto& ctor) { return ctor::Stream(ctor.value()); }); + } + + result_t operator()(const operator_::time::CtorSignedIntegerNs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Time(ctor::Time::Value(ctor.value(), hilti::rt::Time::NanosecondTag())); + }); + } + + result_t operator()(const operator_::time::CtorUnsignedIntegerNs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Time(ctor::Time::Value(ctor.value(), hilti::rt::Time::NanosecondTag())); + }); + } + + result_t operator()(const operator_::time::CtorRealSecs& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::Time(ctor::Time::Value(ctor.value(), hilti::rt::Time::SecondTag())); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned8& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::UnsignedInteger(to_uint64(ctor.value(), p), 8); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned16& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::UnsignedInteger(to_uint64(ctor.value(), p), 16); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned32& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::UnsignedInteger(to_uint64(ctor.value(), p), 32); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorSigned64& op, position_t p) { + return tryReplaceCtorExpression(op, p, [this, &p](const auto& ctor) { + return ctor::UnsignedInteger(to_uint64(ctor.value(), p), 64); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned8& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::UnsignedInteger(ctor.value(), 8); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned16& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::UnsignedInteger(ctor.value(), 16); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned32& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::UnsignedInteger(ctor.value(), 32); + }); + } + + result_t operator()(const operator_::unsigned_integer::CtorUnsigned64& op, position_t p) { + return tryReplaceCtorExpression(op, p, [](const auto& ctor) { + return ctor::UnsignedInteger(ctor.value(), 64); + }); + } +}; + +Result _foldConstant(const Node& expr) { + auto v = VisitorConstantFolder(); + + if ( auto ctor = v.dispatch(expr); ctor && *ctor ) + return **ctor; + else + return result::Error("not a foldable constant expression"); +} + +} // anonymous namespace + +Result> detail::foldConstant(const Node& expr) { + try { + auto v = VisitorConstantFolder(); + + if ( auto ctor = v.dispatch(expr) ) + return *ctor; + else + return {std::nullopt}; + } catch ( const hilti::rt::RuntimeError& e ) { + return result::Error(e.what()); + } +} diff --git a/hilti/toolchain/src/compiler/visitors/normalizer.cc b/hilti/toolchain/src/compiler/visitors/normalizer.cc index 8bbcc89b4..19d632a63 100644 --- a/hilti/toolchain/src/compiler/visitors/normalizer.cc +++ b/hilti/toolchain/src/compiler/visitors/normalizer.cc @@ -1,5 +1,8 @@ // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details. +#include +#include +#include #include #include #include @@ -17,6 +20,37 @@ inline const hilti::logging::DebugStream Normalizer("normalizer"); } // namespace hilti::logging::debug namespace { +struct VisitorConstants : public visitor::PreOrder { + bool modified = false; + + // Log debug message recording resolving a expression. + void logChange(const Node& old, const Ctor& ctor) { + HILTI_DEBUG(logging::debug::Normalizer, + util::fmt("[%s] %s -> constant %s (%s)", old.typename_(), old, ctor, old.location())); + } + + void operator()(const Expression& d, position_t p) { + if ( ! expression::isResolved(d) ) + return; + + if ( d.isA() ) + return; + + auto ctor = detail::foldConstant(p.node); + if ( ! ctor ) { + p.node.addError(ctor.error()); + return; + } + + if ( ! *ctor ) + return; + + logChange(p.node, **ctor); + auto nexpr = expression::Ctor(**ctor, (*ctor)->meta()); + p.node = nexpr; + modified = true; + } +}; struct VisitorNormalizer : public visitor::PreOrder { bool modified = false; @@ -27,6 +61,12 @@ struct VisitorNormalizer : public visitor::PreOrder { util::fmt("[%s] %s -> expression %s (%s)", old.typename_(), old, nexpr, old.location())); } + // Log debug message recording resolving a ctor. + void logChange(const Node& old, const Ctor& nexpr) { + HILTI_DEBUG(logging::debug::Normalizer, + util::fmt("[%s] %s -> ctor %s (%s)", old.typename_(), old, nexpr, old.location())); + } + // Log debug message recording resolving a statement. void logChange(const Node& old, const Statement& nstmt) { HILTI_DEBUG(logging::debug::Normalizer, @@ -44,6 +84,34 @@ struct VisitorNormalizer : public visitor::PreOrder { HILTI_DEBUG(logging::debug::Normalizer, util::fmt("%s -> %s (%s)", old, nattr, old.location())); } + auto callArgument(const expression::ResolvedOperatorBase& o, int i) { + auto ctor = o.op1().as().ctor(); + + if ( auto x = ctor.tryAs() ) + ctor = x->coercedCtor(); + + return ctor.as().value()[i]; + } + + // Helper to cast an uint64 to int64, with range check. + int64_t to_int64(uint64_t x, position_t& p) { + if ( x > static_cast(std::numeric_limits::max()) ) + throw hilti::rt::OutOfRange("integer value out of range"); + + return static_cast(x); + } + + // Overload that doesn't need to do any checking. + int64_t to_int64(int64_t x, position_t& p) { return x; } + + // Helper to cast an int64 to uint64, with range check. + uint64_t to_uint64(int64_t x, position_t& p) { + if ( x < 0 ) + throw hilti::rt::OutOfRange("integer value out of range"); + + return static_cast(x); + } + void operator()(const declaration::Function& u, position_t p) { if ( u.linkage() == declaration::Linkage::Struct ) { // Link method implementations to their parent type. @@ -275,6 +343,13 @@ static void _computeCanonicalIDs(VisitorComputeCanonicalIDs* v, Node* node, ID c bool hilti::detail::ast::normalize(Node* root, Unit* unit) { util::timing::Collector _("hilti/compiler/ast/normalizer"); + auto v0 = VisitorConstants(); + for ( auto i : v0.walk(root) ) + v0.dispatch(i); + + if ( logger().errors() ) + return v0.modified; + auto v1 = VisitorNormalizer(); for ( auto i : v1.walk(root) ) v1.dispatch(i); @@ -291,5 +366,5 @@ bool hilti::detail::ast::normalize(Node* root, Unit* unit) { v4.dispatch(i); #endif - return v1.modified; + return v0.modified || v1.modified; } diff --git a/hilti/toolchain/src/compiler/visitors/printer.cc b/hilti/toolchain/src/compiler/visitors/printer.cc index a90a3d406..a7bac08e4 100644 --- a/hilti/toolchain/src/compiler/visitors/printer.cc +++ b/hilti/toolchain/src/compiler/visitors/printer.cc @@ -14,6 +14,16 @@ using namespace hilti; using util::fmt; +// Global state storing any scopes we are currently in during printing. +// Maintaining this globally isn't great, but because of various independent +// `printAST()` calls happening recursively through `operator<<` and `fmt()`, +// we can't easily pass this state around. +static std::vector _scopes = {""}; + +static const ID& _currentScope() { return _scopes.back(); } +static void _pushScope(ID id) { _scopes.push_back(std::move(id)); } +static void _popScope() { _scopes.pop_back(); } + static std::string renderOperator(operator_::Kind kind, const std::vector& ops) { switch ( kind ) { case operator_::Kind::Add: return fmt("add %s[%s]", ops[0], ops[1]); @@ -164,7 +174,7 @@ struct Visitor : visitor::PreOrder { } void operator()(const ID& n) { - if ( n.namespace_() == out.currentScope() ) + if ( n.namespace_() == _currentScope() ) out << std::string(n.local()); else out << std::string(n); @@ -175,7 +185,7 @@ struct Visitor : visitor::PreOrder { out << "module " << n.id() << " {" << out.newline(); out.endLine(); - out.pushScope(n.id()); + _pushScope(n.id()); auto printDecls = [&](const auto& decls) { for ( const auto& d : decls ) @@ -201,7 +211,7 @@ struct Visitor : visitor::PreOrder { if ( ! n.statements().statements().empty() ) out.emptyLine(); - out.popScope(); + _popScope(); out.beginLine(); out << "}"; @@ -222,11 +232,14 @@ struct Visitor : visitor::PreOrder { out << "default<" << n.type() << ">(" << std::make_pair(n.typeArguments(), ", ") << ")"; } - void operator()(const ctor::Enum& n, position_t p) { out << *p.node.as().typeID() << "::" << n.value(); } + void operator()(const ctor::Enum& n, position_t p) { + assert(n.type().typeID()); + out << *n.type().typeID() << "::" << n.value().id(); + } void operator()(const ctor::Error& n) { out << "error(\"" << n.value() << "\")"; } - void operator()(const ctor::Interval& n) { out << n.value(); } + void operator()(const ctor::Interval& n) { out << "interval_ns(" << n.value().nanoseconds() << ")"; } void operator()(const ctor::List& n) { out << '[' << std::make_pair(n.value(), ", ") << ']'; } @@ -273,7 +286,12 @@ struct Visitor : visitor::PreOrder { void operator()(const ctor::Set& n) { out << "set(" << std::make_pair(n.value(), ", ") << ')'; } - void operator()(const ctor::SignedInteger& n) { out << n.value(); } + void operator()(const ctor::SignedInteger& n) { + if ( n.width() < 64 ) + out << fmt("int%d(%" PRId64 ")", n.width(), n.value()); + else + out << n.value(); + } void operator()(const ctor::Stream& n) { out << "stream(" << util::escapeUTF8(n.value(), true) << ')'; } @@ -295,11 +313,16 @@ struct Visitor : visitor::PreOrder { out << "]"; } - void operator()(const ctor::Time& n) { out << n.value(); } + void operator()(const ctor::Time& n) { out << "time_ns(" << n.value().nanoseconds() << ")"; } void operator()(const ctor::Tuple& n) { out << '(' << std::make_pair(n.value(), ", ") << ')'; } - void operator()(const ctor::UnsignedInteger& n) { out << n.value(); } + void operator()(const ctor::UnsignedInteger& n) { + if ( n.width() < 64 ) + out << fmt("uint%d(%" PRId64 ")", n.width(), n.value()); + else + out << n.value(); + } void operator()(const ctor::Vector& n) { out << "vector(" << std::make_pair(n.value(), ", ") << ')'; } @@ -800,7 +823,7 @@ struct Visitor : visitor::PreOrder { void operator()(const type::Interval& n) { out << const_(n) << "interval"; } - void operator()(const type::Member& n) { out << const_(n) << ""; } + void operator()(const type::Member& n) { out << const_(n) << n.id(); } void operator()(const type::Network& n) { out << const_(n) << "net"; } diff --git a/hilti/toolchain/src/compiler/visitors/resolver.cc b/hilti/toolchain/src/compiler/visitors/resolver.cc index 469325cf3..14a4524c3 100644 --- a/hilti/toolchain/src/compiler/visitors/resolver.cc +++ b/hilti/toolchain/src/compiler/visitors/resolver.cc @@ -576,7 +576,7 @@ bool Visitor::resolveOperator(const expression::UnresolvedOperator& u, position_ modified = true; #ifndef NDEBUG - const Expression& new_op = p.node.as(); + const auto& new_op = p.node.as(); HILTI_DEBUG(logging::debug::Operator, util::fmt("=> resolved to %s (result: %s, expression is %s)", p.node.render(), new_op, (new_op.isConstant() ? "const" : "non-const"))); #endif @@ -912,6 +912,11 @@ std::vector Visitor::matchOverloads(const std::vector& candidate auto r = candidate.instantiate(nops->second, meta); + // Fold any constants right here in case downstream resolving depends + // on finding a constant (like for coercion). + if ( auto ctor = detail::foldConstant(r); ctor && *ctor ) + r = expression::Ctor(**ctor, r.meta()); + // Some operators may not be able to determine their type before the // resolver had a chance to provide the information needed. They will // return "auto" in that case (specifically, that's the case for Spicy diff --git a/spicy/toolchain/src/compiler/parser/parser.yy b/spicy/toolchain/src/compiler/parser/parser.yy index 33779996d..4c2351085 100644 --- a/spicy/toolchain/src/compiler/parser/parser.yy +++ b/spicy/toolchain/src/compiler/parser/parser.yy @@ -34,7 +34,7 @@ namespace spicy { namespace detail { class Parser; } } %verbose %glr-parser -%expect 131 +%expect 125 %expect-rr 164 %{ @@ -239,8 +239,8 @@ static int _field_width = 0; %type local_decl local_init_decl global_decl type_decl import_decl constant_decl function_decl global_scope_decl property_decl hook_decl struct_field %type > struct_fields %type base_type_no_ref base_type type tuple_type struct_type enum_type unit_type bitfield_type reference_type -%type ctor tuple struct_ regexp list vector map set -%type expr tuple_elem tuple_expr member_expr expr_0 expr_1 expr_2 expr_3 expr_4 expr_5 expr_6 expr_7 expr_8 expr_9 expr_a expr_b expr_c expr_d expr_e expr_f expr_g +%type ctor tuple struct_ regexp list vector map set unit_field_ctor +%type expr tuple_elem tuple_expr member_expr ctor_expr expr_0 expr_1 expr_2 expr_3 expr_4 expr_5 expr_6 expr_7 expr_8 expr_9 expr_a expr_b expr_c expr_d expr_e expr_f expr_g %type > opt_tuple_elems1 opt_tuple_elems2 exprs opt_exprs opt_unit_field_args opt_unit_field_sinks %type > opt_else_block %type > opt_init_expression opt_unit_field_condition unit_field_repeat opt_unit_field_repeat opt_unit_switch_expr @@ -273,11 +273,6 @@ static int _field_width = 0; %type , std::vector>> global_scope_items -%type const_real -%type const_uint -%type const_sint - - // Spicy-only %type > opt_unit_field_id %type opt_unit_field_engine opt_hook_engine @@ -288,6 +283,9 @@ static int _field_width = 0; %type unit_switch_case %type > unit_switch_cases +%type const_sint +%type const_uint + %% // Magic states sent by the scanner to provide two separate entry points. @@ -652,7 +650,7 @@ enum_label : local_id { $$ = hilti::type::enum_::Labe | local_id '=' CUINTEGER { $$ = hilti::type::enum_::Label(std::move($1), $3, __loc__); } ; -bitfield_type : BITFIELD '(' const_uint ')' +bitfield_type : BITFIELD '(' CUINTEGER ')' { _field_width = $3; } '{' opt_bitfield_bits '}' { $$ = spicy::type::Bitfield($3, $7, __loc__); } @@ -668,9 +666,9 @@ bitfield_bits | bitfield_bits_spec { $$ = std::vector(); $$.push_back(std::move($1)); } bitfield_bits_spec - : local_id ':' const_uint DOTDOT const_uint opt_attributes ';' + : local_id ':' CUINTEGER DOTDOT CUINTEGER opt_attributes ';' { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $5, _field_width, std::move($6), __loc__); } - | local_id ':' const_uint opt_attributes ';' + | local_id ':' CUINTEGER opt_attributes ';' { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $3, _field_width, std::move($4), __loc__); } /* --- Begin of Spicy units --- */ @@ -715,7 +713,7 @@ unit_field : opt_unit_field_id opt_unit_field_engine base_type opt_unit_fiel $$ = spicy::type::unit::item::UnresolvedField(std::move($1), std::move($3), std::move($2), {}, std::move($4), std::move($7), std::move($5), std::move($6), std::move($8), __loc__); } - | opt_unit_field_id opt_unit_field_engine ctor opt_unit_field_repeat opt_attributes opt_unit_field_condition opt_unit_field_sinks opt_unit_item_hooks + | opt_unit_field_id opt_unit_field_engine unit_field_ctor opt_unit_field_repeat opt_attributes opt_unit_field_condition opt_unit_field_sinks opt_unit_item_hooks { $$ = spicy::type::unit::item::UnresolvedField(std::move($1), std::move($3), std::move($2), {}, std::move($4), std::move($7), std::move($5), std::move($6), std::move($8), __loc__); } | opt_unit_field_id opt_unit_field_engine scoped_id opt_unit_field_args opt_unit_field_repeat opt_attributes opt_unit_field_condition opt_unit_field_sinks opt_unit_item_hooks @@ -724,6 +722,24 @@ unit_field : opt_unit_field_id opt_unit_field_engine base_type opt_unit_fiel | opt_unit_field_id opt_unit_field_engine '(' unit_field_in_container ')' opt_unit_field_repeat opt_attributes opt_unit_field_condition opt_unit_field_sinks opt_unit_item_hooks { $$ = spicy::type::unit::item::UnresolvedField(std::move($1), std::move($4), std::move($2), {}, std::move($6), std::move($9), std::move($7), std::move($8), std::move($10), __loc__); } +const_sint : CUINTEGER { $$ = check_int64_range($1, true, __loc__); } + | '+' CUINTEGER { $$ = check_int64_range($2, true, __loc__); } + | '-' CUINTEGER { $$ = -check_int64_range($2, false, __loc__); } + +const_uint : CUINTEGER { $$ = $1; } + | '+' CUINTEGER { $$ = $2; } + +unit_field_ctor + : ctor { $$ = std::move($1); } + | UINT8 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 8, __loc__); } + | UINT16 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 16, __loc__); } + | UINT32 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 32, __loc__); } + | UINT64 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 64, __loc__); } + | INT8 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 8, __loc__); } + | INT16 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 16, __loc__); } + | INT32 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 32, __loc__); } + | INT64 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 64, __loc__); } + unit_field_in_container : ctor opt_unit_field_args opt_attributes { $$ = spicy::type::unit::item::UnresolvedField({}, std::move($1), {}, std::move($2), {}, {}, std::move($3), {}, {}, __loc__); } @@ -915,8 +931,8 @@ expr_e : CAST type_param_begin type type_param_end '(' expr ')' { $$ = | expr_f { $$ = std::move($1); } expr_f : ctor { $$ = hilti::expression::Ctor(std::move($1), __loc__); } - | PORT '(' expr ',' expr ')' { $$ = hilti::builder::port(std::move($3), std::move($5), __loc__); } - | '-' expr_g { $$ = hilti::expression::UnresolvedOperator(hilti::operator_::Kind::SignNeg, {std::move($2)}, __loc__); } + | ctor_expr { $$ = std::move($1); } + | '-' expr_f { $$ = hilti::expression::UnresolvedOperator(hilti::operator_::Kind::SignNeg, {std::move($2)}, __loc__); } | '[' expr FOR local_id IN expr ']' { $$ = hilti::expression::ListComprehension(std::move($6), std::move($2), std::move($4), {}, __loc__); } | '[' expr FOR local_id IN expr IF expr ']' @@ -943,37 +959,19 @@ ctor : CADDRESS { $$ = hilti::ctor::Address(hil | CPORT { $$ = hilti::ctor::Port(hilti::ctor::Port::Value($1), __loc__); } | CNULL { $$ = hilti::ctor::Null(__loc__); } | CSTRING { $$ = hilti::ctor::String($1, __loc__); } - - | const_real { $$ = hilti::ctor::Real($1, __loc__); } | CUINTEGER { $$ = hilti::ctor::UnsignedInteger($1, 64, __loc__); } - | '+' CUINTEGER { $$ = hilti::ctor::SignedInteger(check_int64_range($2, true, __loc__), 64, __loc__); } - | '-' CUINTEGER { $$ = hilti::ctor::SignedInteger(-check_int64_range($2, false, __loc__), 64, __loc__); } - | OPTIONAL '(' expr ')' { $$ = hilti::ctor::Optional(std::move($3), __loc__); } - | INTERVAL '(' const_real ')' { try { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value($3, hilti::rt::Interval::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value()); error(@$, e.what()); } - } - | INTERVAL '(' const_sint ')' { try { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value($3, hilti::rt::Interval::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value()); error(@$, e.what()); } - } - | INTERVAL_NS '(' const_sint ')' { $$ = hilti::ctor::Interval(hilti::ctor::Interval::Value($3, hilti::rt::Interval::NanosecondTag()), __loc__); } - | TIME '(' const_real ')' { try { $$ = hilti::ctor::Time(hilti::ctor::Time::Value($3, hilti::rt::Time::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Time(hilti::ctor::Time::Value()); error(@$, e.what()); } - } - | TIME '(' const_uint ')' { try { $$ = hilti::ctor::Time(hilti::ctor::Time::Value($3, hilti::rt::Time::SecondTag()), __loc__); } - catch ( hilti::rt::OutOfRange& e ) { $$ = hilti::ctor::Time(hilti::ctor::Time::Value()); error(@$, e.what()); } - } - | TIME_NS '(' const_uint ')' { $$ = hilti::ctor::Time(hilti::ctor::Time::Value($3, hilti::rt::Time::NanosecondTag()), __loc__); } - | STREAM '(' CBYTES ')' { $$ = hilti::ctor::Stream(std::move($3), __loc__); } + | '+' CUINTEGER { if ( $2 > static_cast(std::numeric_limits::max()) ) + hilti::logger().error("integer constant out of range", __loc__.location()); - | UINT8 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 8, __loc__); } - | UINT16 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 16, __loc__); } - | UINT32 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 32, __loc__); } - | UINT64 '(' const_uint ')' { $$ = hilti::ctor::UnsignedInteger($3, 64, __loc__); } - | INT8 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 8, __loc__); } - | INT16 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 16, __loc__); } - | INT32 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 32, __loc__); } - | INT64 '(' const_sint ')' { $$ = hilti::ctor::SignedInteger($3, 64, __loc__); } + $$ = hilti::ctor::SignedInteger($2, 64, __loc__); + } + | CUREAL { $$ = hilti::ctor::Real($1, __loc__); } + | '+' CUREAL { $$ = hilti::ctor::Real($2, __loc__);; } + /* There are more here that we could move into ctor_expr and have them use namedCtor. + But not sure if that'd change much so leaving here for now. + */ + | OPTIONAL '(' expr ')' { $$ = hilti::ctor::Optional(std::move($3), __loc__); } | list { $$ = std::move($1); } | map { $$ = std::move($1); } | regexp { $$ = std::move($1); } @@ -983,16 +981,21 @@ ctor : CADDRESS { $$ = hilti::ctor::Address(hil | vector { $$ = std::move($1); } ; -const_real : CUREAL { $$ = $1; } - | '+' CUREAL { $$ = $2; } - | '-' CUREAL { $$ = -$2; } - -const_sint : CUINTEGER { $$ = check_int64_range($1, true, __loc__); } - | '+' CUINTEGER { $$ = check_int64_range($2, true, __loc__); } - | '-' CUINTEGER { $$ = -check_int64_range($2, false, __loc__); } - -const_uint : CUINTEGER { $$ = $1; } - | '+' CUINTEGER { $$ = $2; } +ctor_expr : INTERVAL '(' expr ')' { $$ = hilti::builder::namedCtor("interval", { std::move($3) }, __loc__); } + | INTERVAL_NS '(' expr ')' { $$ = hilti::builder::namedCtor("interval_ns", { std::move($3) }, __loc__); } + | TIME '(' expr ')' { $$ = hilti::builder::namedCtor("time", { std::move($3) }, __loc__); } + | TIME_NS '(' expr ')' { $$ = hilti::builder::namedCtor("time_ns", { std::move($3) }, __loc__); } + | STREAM '(' expr ')' { $$ = hilti::builder::namedCtor("stream", { std::move($3) }, __loc__); } + | INT8 '(' expr ')' { $$ = hilti::builder::namedCtor("int8", { std::move($3) }, __loc__); } + | INT16 '(' expr ')' { $$ = hilti::builder::namedCtor("int16", { std::move($3) }, __loc__); } + | INT32 '(' expr ')' { $$ = hilti::builder::namedCtor("int32", { std::move($3) }, __loc__); } + | INT64 '(' expr ')' { $$ = hilti::builder::namedCtor("int64", { std::move($3) }, __loc__); } + | UINT8 '(' expr ')' { $$ = hilti::builder::namedCtor("uint8", { std::move($3) }, __loc__); } + | UINT16 '(' expr ')' { $$ = hilti::builder::namedCtor("uint16", { std::move($3) }, __loc__); } + | UINT32 '(' expr ')' { $$ = hilti::builder::namedCtor("uint32", { std::move($3) }, __loc__); } + | UINT64 '(' expr ')' { $$ = hilti::builder::namedCtor("uint64", { std::move($3) }, __loc__); } + | PORT '(' expr ',' expr ')' { $$ = hilti::builder::namedCtor("port", {std::move($3), std::move($5)}, __loc__); } + ; tuple : '(' opt_tuple_elems1 ')' { $$ = hilti::ctor::Tuple(std::move($2), __loc__); } | TUPLE '(' opt_exprs ')' { $$ = hilti::ctor::Tuple(std::move($3), __loc__); } diff --git a/tests/Baseline/hilti.expressions.ctor-replacement/output b/tests/Baseline/hilti.expressions.ctor-replacement/output new file mode 100644 index 000000000..2fcdcd803 --- /dev/null +++ b/tests/Baseline/hilti.expressions.ctor-replacement/output @@ -0,0 +1,34 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[debug/ast-final] # [HILTI] Test: Final AST (round 1) +[debug/ast-final] - Module %4 (ctor-replacement.hlt:6:1-12:2) [@m:XXX] +[debug/ast-final] | Test -> declaration::Module %6 [canon-id: Test] [@d:XXX] ([@d:XXX]) +[debug/ast-final] | x -> declaration::GlobalVariable %1 [canon-id: Test::x] [@d:XXX] ([@d:XXX]) +[debug/ast-final] | y -> declaration::GlobalVariable %2 [canon-id: Test::y] [@d:XXX] ([@d:XXX]) +[debug/ast-final] | z -> declaration::GlobalVariable %3 [canon-id: Test::z] [@d:XXX] ([@d:XXX]) +[debug/ast-final] - ID (ctor-replacement.hlt:6:8) [@i:XXX] +[debug/ast-final] - statement::Block (ctor-replacement.hlt:6:1-12:2) [@s:XXX] +[debug/ast-final] - declaration::GlobalVariable %1 (ctor-replacement.hlt:6:14-8:22) [canon-id: Test::x] [@d:XXX] +[debug/ast-final] - ID (ctor-replacement.hlt:8:8) [@i:XXX] +[debug/ast-final] - node::None (ctor-replacement.hlt:6:14-8:22) [@n:XXX] +[debug/ast-final] - expression::Ctor (ctor-replacement.hlt:8:12) (const) (resolved) [@e:XXX] +[debug/ast-final] - ctor::SignedInteger (ctor-replacement.hlt:8:12) [@c:XXX] +[debug/ast-final] - type::SignedInteger (const) (resolved) [@t:XXX] +[debug/ast-final] - declaration::GlobalVariable %2 (ctor-replacement.hlt:8:22-9:22) [canon-id: Test::y] [@d:XXX] +[debug/ast-final] - ID (ctor-replacement.hlt:9:8) [@i:XXX] +[debug/ast-final] - node::None (ctor-replacement.hlt:6:14-8:22) [@n:XXX] +[debug/ast-final] - expression::Ctor (ctor-replacement.hlt:9:12) (const) (resolved) [@e:XXX] +[debug/ast-final] - ctor::UnsignedInteger (ctor-replacement.hlt:9:12) [@c:XXX] +[debug/ast-final] - type::UnsignedInteger (const) (resolved) [@t:XXX] +[debug/ast-final] - declaration::GlobalVariable %3 (ctor-replacement.hlt:9:22-10:15) [canon-id: Test::z] [@d:XXX] +[debug/ast-final] - ID (ctor-replacement.hlt:10:8) [@i:XXX] +[debug/ast-final] - node::None (ctor-replacement.hlt:6:14-8:22) [@n:XXX] +[debug/ast-final] - expression::Ctor (ctor-replacement.hlt:10:12) (const) (resolved) [@e:XXX] +[debug/ast-final] - ctor::SignedInteger (ctor-replacement.hlt:10:12) [@c:XXX] +[debug/ast-final] - type::SignedInteger (ctor-replacement.hlt:10:12) (const) (resolved) [@t:XXX] +module Test { + +global int<32> x = int32(-1); +global uint<32> y = uint32(1); +global int<64> z = -1; + +} diff --git a/tests/Baseline/hilti.optimization.const/log b/tests/Baseline/hilti.optimization.const/log index 6e20af264..5b75e13d9 100644 --- a/tests/Baseline/hilti.optimization.const/log +++ b/tests/Baseline/hilti.optimization.const/log @@ -1,28 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::f' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' -[debug/optimizer] inlining constant 'Foo::t' [debug/optimizer] removing declaration for unused function hilti::abort [debug/optimizer] removing declaration for unused function hilti::current_time [debug/optimizer] removing declaration for unused function hilti::debug diff --git a/tests/Baseline/hilti.optimization.const/noopt.hlt b/tests/Baseline/hilti.optimization.const/noopt.hlt index 7046f6906..0f7805d0b 100644 --- a/tests/Baseline/hilti.optimization.const/noopt.hlt +++ b/tests/Baseline/hilti.optimization.const/noopt.hlt @@ -6,10 +6,10 @@ import hilti; const bool t = True; const bool f = False; -hilti::print(Foo::t, True); -hilti::print(Foo::f, True); +hilti::print(True, True); +hilti::print(False, True); -if ( t ) { +if ( True ) { 0; } else { @@ -17,7 +17,7 @@ else { } -if ( f ) { +if ( False ) { 2; } else { @@ -25,24 +25,24 @@ else { } -if ( t ) { +if ( True ) { 4; } -if ( f ) { +if ( False ) { 5; } -t || t; -t || f; -f || t; -f || f; -t && t; -t && f; -f && t; -f && f; -! t; -! f; +True; +True; +True; +False; +True; +False; +False; +False; +False; +True; } diff --git a/tests/Baseline/hilti.optimization.unimplemented_hook/noopt.hlt b/tests/Baseline/hilti.optimization.unimplemented_hook/noopt.hlt index 1c720cf87..03c708bba 100644 --- a/tests/Baseline/hilti.optimization.unimplemented_hook/noopt.hlt +++ b/tests/Baseline/hilti.optimization.unimplemented_hook/noopt.hlt @@ -10,7 +10,7 @@ type X = struct { global optional> i = global_unimplemented_int64(); global X x; -global optional> j = Foo::x.unimplemented_int64(); +global optional> j = x.unimplemented_int64(); declare public function hook void global_unimplemented_void(); declare public function hook void global_implemented(); @@ -24,7 +24,7 @@ method hook void X::implemented() { global_implemented(); global_unimplemented_void(); -Foo::x.implemented(); -Foo::x.unimplemented_void(); +x.implemented(); +x.unimplemented_void(); } diff --git a/tests/Baseline/hilti.optimization.unimplemented_hook/opt.hlt b/tests/Baseline/hilti.optimization.unimplemented_hook/opt.hlt index 76ee128cc..90d108357 100644 --- a/tests/Baseline/hilti.optimization.unimplemented_hook/opt.hlt +++ b/tests/Baseline/hilti.optimization.unimplemented_hook/opt.hlt @@ -19,7 +19,7 @@ method hook void X::implemented() { global_implemented(); default(); -Foo::x.implemented(); +x.implemented(); default(); } diff --git a/tests/Baseline/hilti.types.bool.fold/output b/tests/Baseline/hilti.types.bool.fold/output new file mode 100644 index 000000000..e044b4c91 --- /dev/null +++ b/tests/Baseline/hilti.types.bool.fold/output @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +module Test { + +const bool b1 = True; +const bool b2 = False; + +assert True; +assert True; +assert True; +assert True; + +} diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-2/output b/tests/Baseline/hilti.types.integer.ctor-fail-2/output new file mode 100644 index 000000000..e5434e650 --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-2/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:18: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-3/output b/tests/Baseline/hilti.types.integer.ctor-fail-3/output new file mode 100644 index 000000000..b0679a2ac --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-3/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-4/output b/tests/Baseline/hilti.types.integer.ctor-fail-4/output new file mode 100644 index 000000000..8e97ec7e3 --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-4/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer value out of range for type +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-5/output b/tests/Baseline/hilti.types.integer.ctor-fail-5/output new file mode 100644 index 000000000..b0679a2ac --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-5/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-6/output b/tests/Baseline/hilti.types.integer.ctor-fail-6/output new file mode 100644 index 000000000..b0679a2ac --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-6/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-7/output b/tests/Baseline/hilti.types.integer.ctor-fail-7/output new file mode 100644 index 000000000..8e97ec7e3 --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-7/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer value out of range for type +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.ctor-fail-8/output b/tests/Baseline/hilti.types.integer.ctor-fail-8/output new file mode 100644 index 000000000..d118fbe3a --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail-8/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:2:12: integer constant out of range +[error] hiltic: parse error diff --git a/tests/Baseline/hilti.types.integer.ctor-fail/output b/tests/Baseline/hilti.types.integer.ctor-fail/output new file mode 100644 index 000000000..3f962fae9 --- /dev/null +++ b/tests/Baseline/hilti.types.integer.ctor-fail/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.hlt:7:12: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/hilti.types.integer.signed-out-of-range/output b/tests/Baseline/hilti.types.integer.signed-out-of-range/output index 21f48ad00..3fa26244d 100644 --- a/tests/Baseline/hilti.types.integer.signed-out-of-range/output +++ b/tests/Baseline/hilti.types.integer.signed-out-of-range/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/signed-out-of-range.hlt:10:26: signed integer value out of range -[error] hiltic: parse error +[error] <...>/signed-out-of-range.hlt:10:26: integer value out of range +[error] hiltic: aborting after errors diff --git a/tests/Baseline/spicy.optimization.default-parser-functions/noopt.hlt b/tests/Baseline/spicy.optimization.default-parser-functions/noopt.hlt index b1414a65e..7c4814e73 100644 --- a/tests/Baseline/spicy.optimization.default-parser-functions/noopt.hlt +++ b/tests/Baseline/spicy.optimization.default-parser-functions/noopt.hlt @@ -261,7 +261,7 @@ method extern method view foo::P0::parse1(inout value_ref data, method extern method view foo::P0::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/default-parser-functions.spicy:12:11" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::P0)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(P0)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -471,7 +471,7 @@ method extern method view foo::P1::parse1(inout value_ref data, method extern method view foo::P1::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/default-parser-functions.spicy:14:18" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::P1)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(P1)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -745,7 +745,7 @@ method extern method view foo::P2::parse1(inout value_ref data, method extern method view foo::P2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/default-parser-functions.spicy:16:18-21:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::P2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(P2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.default-parser-functions/opt.hlt b/tests/Baseline/spicy.optimization.default-parser-functions/opt.hlt index 489b3c7ee..eebe1f36f 100644 --- a/tests/Baseline/spicy.optimization.default-parser-functions/opt.hlt +++ b/tests/Baseline/spicy.optimization.default-parser-functions/opt.hlt @@ -110,7 +110,7 @@ method extern method view foo::P1::parse1(inout value_ref data, method extern method view foo::P1::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/default-parser-functions.spicy:14:18" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::P1)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(P1)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -265,7 +265,7 @@ method extern method view foo::P2::parse1(inout value_ref data, method extern method view foo::P2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/default-parser-functions.spicy:16:18-21:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::P2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(P2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.feature_requirements/noopt.hlt b/tests/Baseline/spicy.optimization.feature_requirements/noopt.hlt index 56753bd57..9eaeecace 100644 --- a/tests/Baseline/spicy.optimization.feature_requirements/noopt.hlt +++ b/tests/Baseline/spicy.optimization.feature_requirements/noopt.hlt @@ -357,7 +357,7 @@ method extern method view foo::X1::parse1(inout value_ref data, method extern method view foo::X1::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:13:11-15:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X1)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X1)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -567,7 +567,7 @@ method extern method view foo::X2::parse1(inout value_ref data, method extern method view foo::X2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:18:11" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -785,7 +785,7 @@ method extern method view foo::X3::parse1(inout value_ref data, method extern method view foo::X3::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:21:11-23:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X3)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X3)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1003,7 +1003,7 @@ method extern method view foo::X4::parse1(inout value_ref data, method extern method view foo::X4::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:27:11-29:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X4)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X4)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1056,7 +1056,7 @@ init function void __register_foo_X4() { } method hook void foo::X5::__on_0x25_init() { - spicy_rt::filter_connect(self, new foo::X4()); + spicy_rt::filter_connect(self, new X4()); } method method tuple, int<64>, iterator, optional> foo::X5::__parse_stage1(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error) { @@ -1217,7 +1217,7 @@ method extern method view foo::X5::parse1(inout value_ref data, method extern method view foo::X5::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:31:18-35:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X5)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X5)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1429,7 +1429,7 @@ method extern method view foo::X6::parse1(inout value_ref data, method extern method view foo::X6::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:38:11-41:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X6)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X6)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.feature_requirements/opt.hlt b/tests/Baseline/spicy.optimization.feature_requirements/opt.hlt index bbbb910a0..60d4ce7ec 100644 --- a/tests/Baseline/spicy.optimization.feature_requirements/opt.hlt +++ b/tests/Baseline/spicy.optimization.feature_requirements/opt.hlt @@ -164,7 +164,7 @@ method extern method view foo::X4::parse1(inout value_ref data, method extern method view foo::X4::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:27:11-29:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X4)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X4)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -208,7 +208,7 @@ init function void __register_foo_X4() { } method hook void foo::X5::__on_0x25_init() { - spicy_rt::filter_connect(self, new foo::X4()); + spicy_rt::filter_connect(self, new X4()); } method method tuple, int<64>, iterator, optional> foo::X5::__parse_stage1(inout value_ref __data, copy view __cur, copy bool __trim, copy int<64> __lah, copy iterator __lahe, copy optional __error) { @@ -292,7 +292,7 @@ method extern method view foo::X5::parse1(inout value_ref data, method extern method view foo::X5::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:31:18-35:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X5)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X5)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -399,7 +399,7 @@ method extern method view foo::X6::parse1(inout value_ref data, method extern method view foo::X6::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/feature_requirements.spicy:38:11-41:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::X6)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(X6)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt b/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt index 77a4d1530..9744ed3df 100644 --- a/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt +++ b/tests/Baseline/spicy.optimization.unused-functions/noopt.hlt @@ -327,7 +327,7 @@ method extern method view foo::A::parse1(inout value_ref data, o method extern method view foo::A::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:18:10" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::A)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(A)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -537,7 +537,7 @@ method extern method view foo::B::parse1(inout value_ref data, o method extern method view foo::B::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:21:17" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::B)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(B)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -743,7 +743,7 @@ method extern method view foo::C::parse1(inout value_ref data, o method extern method view foo::C::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:24:10" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::C)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(C)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -964,7 +964,7 @@ method extern method view foo::D::parse1(inout value_ref data, o method extern method view foo::D::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:25:17-27:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::D)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(D)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1178,7 +1178,7 @@ method extern method view foo::F::parse1(inout value_ref data, o method extern method view foo::F::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:30:10-32:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::F)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(F)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.unused-functions/opt.hlt b/tests/Baseline/spicy.optimization.unused-functions/opt.hlt index 1fed47133..2be88e9f7 100644 --- a/tests/Baseline/spicy.optimization.unused-functions/opt.hlt +++ b/tests/Baseline/spicy.optimization.unused-functions/opt.hlt @@ -119,7 +119,7 @@ method extern method view foo::B::parse1(inout value_ref data, o method extern method view foo::B::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:21:17" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::B)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(B)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -270,7 +270,7 @@ method extern method view foo::D::parse1(inout value_ref data, o method extern method view foo::D::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-functions.spicy:25:17-27:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::D)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(D)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.unused-types/noopt.hlt b/tests/Baseline/spicy.optimization.unused-types/noopt.hlt index 4eb45c993..6eec7a466 100644 --- a/tests/Baseline/spicy.optimization.unused-types/noopt.hlt +++ b/tests/Baseline/spicy.optimization.unused-types/noopt.hlt @@ -460,7 +460,7 @@ method extern method view foo::Priv1::parse1(inout value_ref dat method extern method view foo::Priv1::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:13:14" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv1)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv1)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -670,7 +670,7 @@ method extern method view foo::Pub2::parse1(inout value_ref data method extern method view foo::Pub2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:16:20" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Pub2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Pub2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -876,7 +876,7 @@ method extern method view foo::Priv2::parse1(inout value_ref dat method extern method view foo::Priv2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:19:14" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1086,7 +1086,7 @@ method extern method view foo::Priv3::parse1(inout value_ref dat method extern method view foo::Priv3::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:20:14" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv3)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv3)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1334,7 +1334,7 @@ method extern method view foo::Priv4::parse1(inout value_ref dat method extern method view foo::Priv4::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:21:14-24:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv4)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv4)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1544,7 +1544,7 @@ method extern method view foo::Priv5::parse1(inout value_ref dat method extern method view foo::Priv5::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:27:14" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv5)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv5)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -1754,7 +1754,7 @@ method extern method view foo::Priv6::parse1(inout value_ref dat method extern method view foo::Priv6::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:28:14" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv6)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv6)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -2002,7 +2002,7 @@ method extern method view foo::Pub3::parse1(inout value_ref data method extern method view foo::Pub3::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:29:20-32:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Pub3)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Pub3)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -2208,7 +2208,7 @@ method extern method view foo::Priv10::parse1(inout value_ref da method extern method view foo::Priv10::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:43:22-46:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv10)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv10)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.optimization.unused-types/opt.hlt b/tests/Baseline/spicy.optimization.unused-types/opt.hlt index 75593b2cf..e9b2fe8f2 100644 --- a/tests/Baseline/spicy.optimization.unused-types/opt.hlt +++ b/tests/Baseline/spicy.optimization.unused-types/opt.hlt @@ -164,7 +164,7 @@ method extern method view foo::Pub2::parse1(inout value_ref data method extern method view foo::Pub2::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:16:20" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Pub2)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Pub2)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -376,7 +376,7 @@ method extern method view foo::Pub3::parse1(inout value_ref data method extern method view foo::Pub3::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:29:20-32:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Pub3)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Pub3)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; @@ -477,7 +477,7 @@ method extern method view foo::Priv10::parse1(inout value_ref da method extern method view foo::Priv10::parse3(inout value_ref gunit, inout value_ref data, optional> cur = Null, optional context) &needed-by-feature="is_filter" &needed-by-feature="supports_sinks" &static { # "<...>/unused-types.spicy:43:22-46:2" local value_ref unit = value_ref(default())value_ref(default()); - spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(foo::Priv10)); + spicy_rt::initializeParsedUnit(gunit, unit, typeinfo(Priv10)); local view ncur = cur ? (*cur) : cast>((*data)); local int<64> lahead = 0; local iterator lahead_end; diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-10/output b/tests/Baseline/spicy.types.integer.ctor-fail-10/output new file mode 100644 index 000000000..880fbf4f8 --- /dev/null +++ b/tests/Baseline/spicy.types.integer.ctor-fail-10/output @@ -0,0 +1,5 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.spicy:3:16: integer value out of range for type +[error] <...>/ctor-fail.spicy:4:17: integer value out of range for type +[error] <...>/ctor-fail.spicy:5:17: integer value out of range for type +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-2/output b/tests/Baseline/spicy.types.integer.ctor-fail-2/output index ca4ed0d35..3a42ba3a4 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-2/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-2/output @@ -5,5 +5,5 @@ [error] <...>/ctor-fail.spicy:1:38: invalid character [error] <...>/ctor-fail.spicy:1:38: invalid character [error] <...>/ctor-fail.spicy:1:38: invalid character -[error] <...>/ctor-fail.spicy:1:38: syntax error, unexpected ')', expecting unsigned integer value or '+' +[error] <...>/ctor-fail.spicy:1:38: syntax error, unexpected ')' [error] spicyc: parse error diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-3/output b/tests/Baseline/spicy.types.integer.ctor-fail-3/output index 68a9492d5..12c14cb18 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-3/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-3/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/ctor-fail.spicy:1:34: syntax error, unexpected '-', expecting unsigned integer value or '+' -[error] spicyc: parse error +[error] <...>/ctor-fail.spicy:1:28: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-4/output b/tests/Baseline/spicy.types.integer.ctor-fail-4/output index f4e27962c..192f0e686 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-4/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-4/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/ctor-fail.spicy:1:36: syntax error, unexpected '-', expecting unsigned integer value or '+' -[error] spicyc: parse error +[error] <...>/ctor-fail.spicy:1:29: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-5/output b/tests/Baseline/spicy.types.integer.ctor-fail-5/output index 68a9492d5..2210b8cd4 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-5/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-5/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/ctor-fail.spicy:1:34: syntax error, unexpected '-', expecting unsigned integer value or '+' -[error] spicyc: parse error +[error] <...>/ctor-fail.spicy:1:27: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-6/output b/tests/Baseline/spicy.types.integer.ctor-fail-6/output index f4e27962c..192f0e686 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-6/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-6/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/ctor-fail.spicy:1:36: syntax error, unexpected '-', expecting unsigned integer value or '+' -[error] spicyc: parse error +[error] <...>/ctor-fail.spicy:1:29: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-8/output b/tests/Baseline/spicy.types.integer.ctor-fail-8/output index 2cc7999b6..a02d1221b 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail-8/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail-8/output @@ -1,4 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/ctor-fail.spicy:5:23: signed integer value out of range -[error] <...>/ctor-fail.spicy:6:23: signed integer value out of range -[error] spicyc: parse error +[error] <...>/ctor-fail.spicy:4:17: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail-9/output b/tests/Baseline/spicy.types.integer.ctor-fail-9/output new file mode 100644 index 000000000..e9a2cbe6b --- /dev/null +++ b/tests/Baseline/spicy.types.integer.ctor-fail-9/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.spicy:3:23: integer value out of range +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.integer.ctor-fail/output b/tests/Baseline/spicy.types.integer.ctor-fail/output index 6d7d2f8db..0e493c71c 100644 --- a/tests/Baseline/spicy.types.integer.ctor-fail/output +++ b/tests/Baseline/spicy.types.integer.ctor-fail/output @@ -5,7 +5,4 @@ [error] <...>/ctor-fail.spicy:13:16: integer value out of range for type [error] <...>/ctor-fail.spicy:14:17: integer value out of range for type [error] <...>/ctor-fail.spicy:15:17: integer value out of range for type -[error] <...>/ctor-fail.spicy:18:16: integer value out of range for type -[error] <...>/ctor-fail.spicy:19:17: integer value out of range for type -[error] <...>/ctor-fail.spicy:20:17: integer value out of range for type [error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.interval.ctor-out-of-range/output b/tests/Baseline/spicy.types.interval.ctor-out-of-range/output index 028b73376..78c4be0c9 100644 --- a/tests/Baseline/spicy.types.interval.ctor-out-of-range/output +++ b/tests/Baseline/spicy.types.interval.ctor-out-of-range/output @@ -1,4 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. [error] <...>/ctor-out-of-range.spicy:7:12: value cannot be represented as an interval [error] <...>/ctor-out-of-range.spicy:8:12: value cannot be represented as an interval -[error] spicyc: parse error +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.vector.parse-lahead-int-ambiguous/output b/tests/Baseline/spicy.types.vector.parse-lahead-int-ambiguous/output index 41c8d1a05..d6c802e7d 100644 --- a/tests/Baseline/spicy.types.vector.parse-lahead-int-ambiguous/output +++ b/tests/Baseline/spicy.types.vector.parse-lahead-int-ambiguous/output @@ -1,4 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/parse-lahead-int-ambiguous.spicy:12:1-17:7: grammar HTTP::Test (<...>/parse-lahead-int-ambiguous.spicy:12:1-17:7), production a_l1 (<...>/parse-lahead-int-ambiguous.spicy:13:5) is ambiguous for look-ahead symbol(s) { 1 (uint<8>) } +[error] <...>/parse-lahead-int-ambiguous.spicy:12:1-17:7: grammar HTTP::Test (<...>/parse-lahead-int-ambiguous.spicy:12:1-17:7), production a_l1 (<...>/parse-lahead-int-ambiguous.spicy:13:5) is ambiguous for look-ahead symbol(s) { uint8(1) (uint<8>) } [error] spicyc: aborting after errors diff --git a/tests/hilti/expressions/ctor-replacement.hlt b/tests/hilti/expressions/ctor-replacement.hlt new file mode 100644 index 000000000..9c789fec5 --- /dev/null +++ b/tests/hilti/expressions/ctor-replacement.hlt @@ -0,0 +1,12 @@ +# @TEST-EXEC: hiltic -p -D ast-final %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Check that the constant folder replaces constant expressions with corresponding ctor nodes, and that the printer round-trips the result. + +module Test { + +global x = int32(-1); +global y = uint32(1); +global z = -1; # int64 + +} diff --git a/tests/hilti/types/bool/fold.hlt b/tests/hilti/types/bool/fold.hlt new file mode 100644 index 000000000..ac75cfff5 --- /dev/null +++ b/tests/hilti/types/bool/fold.hlt @@ -0,0 +1,17 @@ +# @TEST-EXEC: hiltic -p %INPUT >>output +# @TEST-EXEC: hiltic -j %INPUT >>output +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Test boolean constant folding. + +module Test { + +const b1 = (True || False); +const b2 = (True && False); + +assert True && True; +assert (True && (False || (!False))); +assert b1 || b2; +assert !(b1 && b2); + +} diff --git a/tests/hilti/types/integer/cast.hlt b/tests/hilti/types/integer/cast.hlt index 1cc7603a3..bf262d50b 100644 --- a/tests/hilti/types/integer/cast.hlt +++ b/tests/hilti/types/integer/cast.hlt @@ -12,7 +12,7 @@ i = cast>(j); assert j == 32; assert i == 32; -global auto x = int<8>(5); +global auto x = int8(5); global int<8> y = 5; assert x == y; } diff --git a/tests/hilti/types/integer/ctor-fail.hlt b/tests/hilti/types/integer/ctor-fail.hlt new file mode 100644 index 000000000..231dc7da1 --- /dev/null +++ b/tests/hilti/types/integer/ctor-fail.hlt @@ -0,0 +1,43 @@ +# @TEST-EXEC-FAIL: ${HILTIC} -j %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Test a series of out-of-range integer constructors. + +module Test { +global x = int64(9223372036854775808); # max_int64 + 1 +} + +@TEST-START-NEXT +module Test { +global x = int64(-9223372036854775809); # min_int64 - 1 +} + +@TEST-START-NEXT +module Test { +global x = uint64(-1); +} + +@TEST-START-NEXT +module Test { +global x = uint8(256); +} + +@TEST-START-NEXT +module Test { +global x = uint8(-256); +} + +@TEST-START-NEXT +module Test { +global x = uint8(-1); +} + +@TEST-START-NEXT +module Test { +global x = int8(128); +} + +@TEST-START-NEXT +module Test { +global x = +9223372036854775808; +} diff --git a/tests/hilti/types/integer/operators-signed.hlt b/tests/hilti/types/integer/operators-signed.hlt index 2914829c3..3225a36a7 100644 --- a/tests/hilti/types/integer/operators-signed.hlt +++ b/tests/hilti/types/integer/operators-signed.hlt @@ -53,4 +53,19 @@ assert i == -30; i /= 3; assert i == -10; +global uint<64> u = 10; +assert int8(20) == int8(2 * u); +assert int16(20) == int16(2 * u); +assert int32(20) == int32(2 * u); +assert int64(20) == int64(2 * u); + +global int<64> s = 10; +assert int8(20) == int8(2 * s); +assert int16(20) == int16(2 * s); +assert int32(20) == int32(2 * s); +assert int64(20) == int64(2 * s); + +# Check that max/min doesn't trigger an error. +global x = int64(9223372036854775807); # max_int64 +global y = int64(-9223372036854775808); # min_int64 } diff --git a/tests/hilti/types/integer/operators-unsigned.hlt b/tests/hilti/types/integer/operators-unsigned.hlt index a9be9d642..01d466ec5 100644 --- a/tests/hilti/types/integer/operators-unsigned.hlt +++ b/tests/hilti/types/integer/operators-unsigned.hlt @@ -58,4 +58,16 @@ assert i == 30; i /= 3; assert i == 10; +global uint<64> u = 10; +assert uint8(20) == uint8(2 * u); +assert uint16(20) == uint16(2 * u); +assert uint32(20) == uint32(2 * u); +assert uint64(20) == uint64(2 * u); + +global uint<64> s = 10; +assert uint8(20) == uint8(2 * s); +assert uint16(20) == uint16(2 * s); +assert uint32(20) == uint32(2 * s); +assert uint64(20) == uint64(2 * s); + } diff --git a/tests/hilti/types/interval/ops.hlt b/tests/hilti/types/interval/ops.hlt index 21ed494b9..a92da8704 100644 --- a/tests/hilti/types/interval/ops.hlt +++ b/tests/hilti/types/interval/ops.hlt @@ -7,6 +7,8 @@ import hilti; global i1 = interval(2.5); global i2 = interval(1.5); +global i3 = interval(10 + 15); +global i4 = interval(10.0 + 15.0); hilti::print(i1); hilti::print(i2); @@ -28,5 +30,11 @@ assert i1 >= i1; assert i2 <= i2; assert cast(5) == interval(5.0); +assert cast(5.5) == interval(5.5); + +assert i3 == interval(25.0); +assert i3 == i4; + +assert interval_ns(2500000000) == i1; } diff --git a/tests/hilti/types/result/error.hlt b/tests/hilti/types/result/error.hlt index 9bb33f0f5..7d893c6c3 100644 --- a/tests/hilti/types/result/error.hlt +++ b/tests/hilti/types/result/error.hlt @@ -10,4 +10,7 @@ global auto e = error("test"); hilti::print(e); hilti::print(e.description()); +global s = " 2"; +assert error("test 2").description() == error("test" + s).description(); + } diff --git a/tests/hilti/types/stream/ops.hlt b/tests/hilti/types/stream/ops.hlt index 4c70592c4..a2bb15d68 100644 --- a/tests/hilti/types/stream/ops.hlt +++ b/tests/hilti/types/stream/ops.hlt @@ -55,4 +55,8 @@ function void p(stream x) { global stream x2 = stream(b"abc"); p(x2); +global auto q = b"def"; +global auto qq = stream(b"abc" + q); +assert |qq| == 6 && qq.starts_with(b"abcdef"); + } diff --git a/tests/hilti/types/time/ops.hlt b/tests/hilti/types/time/ops.hlt index 5331738bb..0be8d6da1 100644 --- a/tests/hilti/types/time/ops.hlt +++ b/tests/hilti/types/time/ops.hlt @@ -12,6 +12,7 @@ global i2 = interval(-110.5); hilti::print(t1); assert t1.seconds() == 1295415110.5; assert t1.nanoseconds() == cast>(1295415110.5 * 1e9); +assert time_ns(1295415110500000000) == t1; hilti::print(t1+i); hilti::print(time(1295418710)); @@ -31,4 +32,8 @@ assert t1 <= t1; assert cast