Releases: rail5/bashpp
Releases · rail5/bashpp
Release list
v0.8.12
- Correct and clarify spec page on dynamic casts
Previously, the spec page was incorrect: it claimed that the result
of the cast (i.e., the value to which the directive expands) would be
'an exact copy of INPUT' if valid. This is not and never was accurate,
although it happened to be correct for the majority of actual cases.
The truth of it is this: pointers in Bash++ are implicitly
dereferenced as needed, and the dynamic cast would chase any
arbitrarily long chain of pointers until it arrived finally at the
actual object itself. Then, if the cast was valid, the result would be
the actual address of that object. Obviously, for the vast majority
of real-world cases, the INPUT to a dynamic cast will be, directly,
the address of the object to be cast, so this small difference might
never have been noticed. - bpp-lsp: Update LSP to 3.18 standard
Now that the LSP spec v3.18 has been finalized, upgrade our local
metaModel (used to generate the LSP implementation) to the 3.18
version from 3.17
This does not result in any functional changes. - Minor optimization: no need to allocate when retrieving source file
lists
Previously, bpp_program::get_source_files() concatenated all keys
from the std::unordered_map to return a new vector
We can skip all that using C++23's fancy "range views", which means
no copies and no allocations - Bug fix: calling 'delete' on pointers
Previously, the generated reference code for the pointer was
duplicated
Fix this by guarding the first portion of codegen under the
condition that the second portion will not run (which in this case
is a check for whether the object is explicitly a nonprimitive vs
if it's a pointer)
Relevant test case ('delete') was amended to check this - Codegen: remove global object counter
The object counter was a relic from earlier versions of the compiler.
In the current implementation (that is, the latest-released version),
the counter is completely unnecessary.
This change makes an object's (or pointer's) address completely
determined by properties of the Object entity, without reference to
any mutable state at the time of code generation (e.g., the number
of objects we've already instantiated, etc)
This, incidentally, is also a bug fix.- File A instantiates object 1
- File A dynamically includes file B
- File B instantiates object 2
Since file B is dynamically included, the two units are compiled
separately. When File B is compiled, its object counter never goes
higher than 1 -- it only ever instantiates a single object. When
File A is compiled, by the time we reach object 2, our object
counter has already been incremented once by an earlier object
instantiation. Therefore the two counters disagree with each other,
and when File A later references object 2, it guesses the wrong
address. Removing any dependency on mutable codegen state for
address determination means that the two units, despite being
independently compiled, will always agree on an object's address.
- bpp-lsp: Remove dependency on libfrozen
We can use a simple std::array and linear searches, libfrozen was
overkill for this
v0.8.11
- Performance:
- Entity inheritance refactored to use lazy parent-chain symbol lookup,
completely eliminating the copying of object and class maps during
inheritance. Compile time on a development machine for a 2.4-million-line
generated source file dropped from ~30 minutes to ~22 seconds. - bpp-lsp's ProgramPool now subsumes earlier ASTs when a more complete
program includes the same file, avoiding duplicate program entities
and reducing memory pressure
- Entity inheritance refactored to use lazy parent-chain symbol lookup,
- bpp-lsp:
- Added -j/--threads option to control the size of the worker thread pool
- Cross-program entity resolution for references and renaming: we now
search all programs associated with the given source file for reference
or when workspace renames were requested - Fixed a bug in hover requests where a datamember could be
misinterpreted as a non-datamember object - Handle didSave notifications to free resources that track unsaved
changed - Includes that fail to parse are now tracked, allowing diagnostics to be
properly updated when the included file is fixed. - ProgramPool now supports multiple programs per source file (Closes: #23)
File changes trigger re-parses and diagnostics for all associated
programs. - Added support for DocumentSymbols requests
- Shutdown procedure now strictly follows the LSP spec: the server waits
for an exit notification after acknowledging a shutdown request, and
exits with the correct (spec-mandated) status codes. - ResponseError is now an optional field in protocol messages, in line
with the LSP spec
- VSCode extension:
- Added support for the language server's -j/--threads option
- The -b option (target Bash version) and -j option are now gated behind
version checks, with a warning when the installed server is too old
- Documentation and spec:
- New spec page on value categories (lvalues vs. rvalues)
- Clarified the semantic meaning of 'super', including its behavior
when explicitly dereferenced - Clarified operator expansion rules: replaced ambiguous wording regarding
the "output" of an operator with a more explicitly-defined statement
about an operator's "result" and how it expands in shell contexts - Corrected wordings in the spec pages for methods and supershells
- Build system:
- Refactored manpage generation with pattern rules, allowing parallel
builds. Make target renamed from 'manual' to 'manpages'
- Refactored manpage generation with pattern rules, allowing parallel
- Code hygiene and modernization:
- Split the monolithic bpp.h header into several smaller, focused headers
- Removed the internal fake "primitive" class; primitives are now
represented by class == nullptr, aligning the implementation with the
language's model
v0.8.10
- Performance: Significant compiler speed-ups from multiple optimizations:
- Entity inheritance now pre-reserves map space and uses std::copy()
instead of repeated dynamic allocations, yielding a combined speedup
of over 200% on large source files. - The old bpp_entity::get_objects() interface, which merged and copied
local and foreign object maps, has been removed. Replaced by separate
get_local_objects() and get_foreign_objects() returning const
references, avoiding unnecessary allocations and copies (roughly 2x
speedup on large data). - bpp_entity::get_classes(), get_datamember() and get_method() now return
const references instead of copies. - bpp-lsp now obtains class names directly from map keys, eliminating an
indirection through bpp_class::get_name(). - AST node type handling refactored from a virtual function to a
non-virtual base-class member, reducing indirection. - Replaced unnecessary dynamic casts with static casts when the pointer
type is already known at compile time.
- Entity inheritance now pre-reserves map space and uses std::copy()
- Compiler & language semantics:
- Dynamic includes that fail at runtime now print an error to stderr and
terminate with a non-zero exit code, in line with the language spec. - Lexer/parser bug fix: whitespace and comments are now allowed after
include/include_once directives. - stdlib: corrected a copy-paste error in SharedObject's start-up checks
(was referencing "SharedArray" instead of "SharedObject").
- Dynamic includes that fail at runtime now print an error to stderr and
- Debian packaging:
- Added Homepage field pointing to bpp.sh.
- Standards-Version updated to 4.7.0.
- Removed explicit "Priority: optional" (now the default in dpkg).
- Build system:
- Compiler and flags are now overridable (
?=) to ease cross-compilation
and use of non-GNU toolchains. Thanks to @Nizarjh for the patches. - Cleaner fallback logic for obtaining version information when
dpkg-parsechangelog is unavailable.
- Compiler and flags are now overridable (
- Test suite:
- The runner now explicitly checks for Perl-compatible regex support
in system grep before any tests are executed, failing with a clear
message when support is missing (related to #15). - Test suite switched to angle-bracket includes and
-Istdlib/to test
the local standard library, leveraging the new include-path ordering,
rather than relying on quoted includes with a long../../series,
as we did before.
- The runner now explicitly checks for Perl-compatible regex support
- Code hygiene & modernization:
- Replaced manual linear searches with std::erase_if and
std::ranges::contains. - Replaced legacy
const char*arrays with constexpr
std::arraystd::string_view for type safety. - Converted bpp.h enums to enum class; omitted unused parameter names in
listener handlers. - Introduced a bpp_assert macro that compiles away with NDEBUG; replaced
explicit dynamic_pointer_cast + InternalError patterns with a template
helper that becomes a zero-cost static cast in release builds (note:
NDEBUG builds will not be shipped before v1.0.0). - Renamed the entity "objects" map to "foreign_objects" to better convey
ownership intent. - Copyright headers standardized with SPDX-License-Identifier and cleaned
up formatting; removed extraneous asterisks that leaked into Doxygen
documentation. - Pass const reference in ErrorOrWarning::set_from_listener to avoid a
full copy; prevent overflow in BashVersion parsing; declare NullBuffer
constructors/destructor noexcept. - Minor style improvements: std::ranges::reverse_view, emplace_back for
temporaries, removed unused includes.
- Replaced manual linear searches with std::erase_if and
v0.8.9
- Subshell code generation: Fixed critical bug where normal command
substitution subshells ($(...)) and cat‑replacement subshells
($(< file)) incorrectly shared buffer placement logic.- Cat‑replacement subshells now enforce perfect forwarding: pre‑code
and post‑code are placed strictly outside the substitution, and
local object destruction is deferred until after buffers are flushed. - Normal subshells now correctly scope pre‑code, post‑code, and
destructor calls inside the substitution, ensuring proper lifetime
management and output capture. - Added test cases for cat‑replacement and corrected expectations in
the local‑scope test.
- Cat‑replacement subshells now enforce perfect forwarding: pre‑code
- AST pretty‑printing: SubshellSubstitution nodes now display whether
they represent a cat‑replacement subshell, aiding debugging. - Parser error recovery: The parser now attempts to recover from syntax
errors and continue building the AST, allowing multiple parser errors to
be reported in a single compilation pass rather than aborting on the
first failure. - bpp‑lsp improvements:
- Removed unused
--portand--socketoptions; the language server
now communicates exclusively over stdio. - Eliminated unnecessary signal handlers; the server simply exits on
signals as no extra cleanup is required. - Added a note to the help text describing LSP usage.
- Removed unused
- Code hygiene and refactoring:
- Replaced
system()withfork()+execvp()for runs-on-exit - Changed
in_supershellboolean flag to astack<std::monostate>
to correctly track nested supershell contexts. - Unified multiple
NullOStreamimplementations into a single common
definition. - Migrated from
realpath()tostd::filesystem::canonical(). - Refined argument parsing: Bash version string parsing moved into a
constexprconstructor ofBashVersion.
- Replaced
v0.8.8
- Spec: Automatic object lifetime management is now explicitly
defined by the spec. Destructors will automatically be called for
scope-local objects at the end of all scoped constructs, including:
Plain bash functions, class methods, curly-braced blocks, subshells,
process substitutions, and all control-flow constructs (if/else, while
until, for, case, select).
Some of these cases were not properly handled before, having the spec
state explicitly what the behavior should be helps us to verify that
the compiler is behaving properly. - Spec: Define explicitly that objects instantiated within a supershell
are owned (and therefore have their lifetimes managed) by the
code entity containing that supershell, not by the supershell itself.
Having this defined also illuminated another bug: namely, that the
compiler didn't do this. This is therefore also a bug fix. To this end,
an internal adopt() function was added to bpp::bpp_code_entity,
used by parent scopes to adopt the objects instantiated by supershells
that they contain. - Include path handling: The standard library directory is now always the
last include path, allowing user-supplied-Idirectories to override
standard library files. This behavior is now consistent between both the
compiler and the language server. - Lexer bug fix: Correctly exit the class-header lexer mode after a class
declaration that does not inherit from a parent class. This resolves
a parser failure where ':' no-op commands would appear later in the
source. - Redirections and pipes with compound constructs: Fixed a bug where 'if'
and 'case' statements would incorrectly append delimiters after their
terminal tokens (that is, after 'fi', 'esac').
Added relevant test case for redirections and pipes into and out of
all compound shell constructs (if, while, until, for, select, and case) - bpp-lsp: The 'UTF16' flag is now correctly propagated to included files.
- Code hygiene (internal): Replaced legacy .rfind()/.find() string checks
with modern .starts_with()/.contains()
Removed unused include directives and commented out unused function
parameters.
Updated vendored XGetOpt version to 1.0.1 - Documentation: Added comprehensive spec pages on scope and object
lifetime management.
Clarified the definition of 'system methods'
Updated compiler and language manuals to reflect new include path
behavior.
v0.8.7
- Lexer bug fix: Only register elif/else/fi as keywords if they're
lvalues - Build system: Simplified and generalized build system with
auto-discovered sources
Refactored the build system to remove per- directory object rules
and replace them with a single generic pattern that mirrors the
source tree into bin/obj. - Code style improvements:
Replaced global bpp_exit_code with data member of the Listener class
Replaced pointer arithmetic in parse_arguments() with std::span usage
Added default case to xgetopt switch
No need to explicitly default virtual destructors for LSP message
base types
Explicit member initialization everywhere
Use emplace_back() for temporaries
Explicitly handle ownership semantics in BashppParser
Use BashppParser.setInputFromFilePath instead of from FilePtr where
ownership may be ambiguous
bpp-lsp: Moved URI validation to freestanding function
Option parsing: Allow non-regular files (such as /dev/null) for output,
just check whether we have write permission - Test suite: Added '-c' option to benchmark compile times without actually
running the compiled tests - Parser: error out of datamember declarations when given an lvalue object
reference instead of a proper object instantiation
v0.8.6
- Supershells: Preserve stderr as subshells do
Supershells in Bash++ now handle stderr identically to subshell
substitution, matching Bash 5.3's native supershells.
Previously, supershells in 5.2-compatibility mode discarded stderr; now it
is preserved.
Added regression test for supershell stderr handling. - Dynamic cast codegen: Don't force-quote reference code
Fixed edge-case bug where generated code for dynamic casts would
incorrectly add quotes around the reference code. Now preserves original
quoting as written in source.
Added regression test for dynamic cast quoting. - Parser: Never override lexer's positive lvalue judgment
Fixed bug where parser could incorrectly override the lexer's
determination that a token could be an lvalue.
Ensures correct handling of lvalue/rvalue distinctions, especially around
redirections and pipes.
Added regression test for this behavior. - Test suite: Run tests for Bash 5.2 and 5.3
Tests are now run twice if Bash >=5.3 is installed:
once for 5.2 compatibility, once for 5.3.
v0.8.5
- Bug fix: bpp-lsp: Don't re-throw exceptions
When the input stream is unexpectedly halted, make sure we go through our
necessary clean-up procedure. Re-throwing the received exception in this
case would suddenly halt the program sans clean-up. - Bug fix: bpp: Concatenated lvalues in the parser
Updated the parser grammar to allow operative command words to be
composed of multiple adjacent tokens, matching Bash's behavior for
command names.
Added accompanying regression test - Replaced homegrown CLI option parsing with XGetOpt
Vendored XGetOpt header in src/include
v0.8.4
- Lexer/Parser/AST:
Full and proper support for array indexing in object references and lvalue
assignments; parser and listener logic updated accordingly.
Bug fix: Properly lex isolated digits in heredoc content and escaped dollar
signs in string interpolations.
Improved error handling: Parser errors are now propagated to listeners and
main program logic, enabling better diagnostics and LSP support.
Added new test cases for parser errors and self-reference outside of class
context.
Bug fix: Verify we're inside a class if processing a self-reference.
Improved output line comparison in the test suite. - Standard Library:
All containeremptymethods now return status code
(0 if empty, 1 otherwise) instead of echoing "true"/"false", for
shell-friendly checks.
Documentation and test cases updated to reflect newemptymethod behavior
Consistent return conventions across Array, Stack, Queue, SharedArray,
SharedStack, SharedQueue, SharedVar, TypedArray, TypedStack, and TypedQueue - Documentation:
Added and clarified language specification pages, including a new page on
the "entity" concept.
Improved CONTRIBUTING.md with style guidelines and examples.
Added PR template and clarified how to add test cases. - Language Server:
Bug fix: If the input stream is halted, clean up and exit rather than
hanging.
Improved debounce logic for didChange notifications.
Bug fix: Provide completions after 'this'/'super' keywords.
Improved error propagation and diagnostics for parser errors.
v0.8.3
- Internal system methods refactored:
Treat all internal system methods (such as __new, __delete, __copy) as
ordinary methods. - Removed special-casing for system methods; they are now generated,
overridden, and dispatched using the same mechanisms as user-defined
methods. - Improved method override and inheritance logic for system methods, ensuring
correct virtual/override semantics. - Refactored code generation for object creation, deletion, and copying to
use generated methods (__new, __delete, __copy) instead of templates or
global functions. - Enhanced constructor and destructor handling for better inheritance and
chaining. - Added comprehensive regression tests for copy, delete, and constructor
chaining behaviors. - Code cleanup and improved error propagation in method prologues.