NOTE: This language is still in the infant stage and it is _NOT_ recommended to use in any real or professional capacity.
NOTE: As of now, the only supported platform is Linux, and no guarantees for MacOS.
NOTE: (If contributing) do not modify the README.html
as it is auto generated from README.org
by Emacs Org Mode.
NOTE: Open README.html
in a browser to view this document in a much better format.
EARL (Evaluate And Run Language) is a gradually typed programming language that introduces higher level programming concepts to BASH scripting, and designed to replace BASH scripts. It is most similar to Python and Rust but is gradually typed.
It has (and plans to have):
- [X] Object Oriented Programming
- [X] fully interactive REPL
- [X] standard library
- [X] syntax highlighting for common editors (VSCode, Emacs, Vim, NeoVim)
- [X] extensive documentation
- [-] package manager (WIP) (see https://github.com/malloc-nbytes/earlmgr)
- [-] the ability to be translated to Python (WIP) (see the
--to-py
flag inearl --help
)
This examples performs
ls -lah
and takes the permissions and the filename and prints them.Here is the BASH version:
files=$(ls -lah) echo "$files" | while read -r line; do # Skip the header if [[ "$line" =~ ^total ]]; then continue fi permissions=$(echo "$line" | awk '{print $1}') filename=$(echo "$line" | awk '{print $9}') echo "Permissions: $permissions - File: $filename" doneAnd here is the EARL version:
$"ls -lah" |> let files; foreach f in files.split("\n")[1:] { let parts = f.split(" "); let permissions, filename = (parts[0], parts.back()); println(f"Permissions: {permissions} - File: {filename}"); }
This is a script to list processes matching the given input and asks which one(s) to kill:
module Main import "std/script.rl"; as scr fn handle_input(num, candidates) { if num == 'a' || num == "all" { let pids = candidates.map(|info| {return info[0];}); for i in 0 to len(pids) { println("killing: ", candidates[i]); $"kill " + str(pids[i]); } } else if num == 'q' || num == "quit" { println("quitting..."); exit(0); } else { let idx = int(num); if idx < 0 || idx >= len(candidates) { panic(f"index {idx} is out of range of length ", len(candidates)); } println("killing: ", candidates[idx]); $"kill " + str(candidates[idx][0]); } } if len(argv()) < 2 { panic("Usage: ", argv()[0], " <proc>"); } let max_display_chars, program_name = ( 50, # Truncate output because it can get long argv()[1], # User supplied CLI arg ); # Get all PIDs and process names let candidates = scr::get_pid(program_name) .rev()[1:] # Cut off this earl proc .rev(); # Undo rev if len(candidates) == 0 { println("no processes found"); exit(0); } println( "Choose a number or list of numbers, `a` for all, or `q` to quit" ); for i in 0 to len(candidates) { let pid, cmd = ( candidates[i][0], candidates[i][1], ); if len(cmd) > max_display_chars { println(f" {i}: ({pid}, ", cmd.substr(0, max_display_chars), "...)"); } else { println(f" {i}: ({pid}, {cmd})"); } } # Handle user input input("[a(ll), q(uit), ", 0, '-', len(candidates)-1, "]: ") .split(" ") # could have multiple inputs .filter(|s|{return s != "";}) # remove empty entries .foreach(|k|{handle_input(k, candidates);});
For the manual on how to use the language, see Click here for the EARL Language Reference.
We have moved from autotools
to cmake, so the new required tools are:
c++17
cmake
(at least v3.25.1)doxygen
(optional) (for c++ source code documentation [good for doing development on the interpreter])
Users compiling for the first time should do
cd EARL
mkdir build
cd build
cmake -S ../ -B .
Note: You can also supply a prefix
option to changed the default installation location (/usr/local
) by using -DINSTALL_PREFIX=<prefix>
.
However, there must be an =include/= and =bin/= directory inside of the prefix that is supplied.
This will create the Makefile. Use make <opt>
where <opt>
is one of,
make
→ builds the projectmake clean
→ cleans the projectmake test
→ build the project and runs tests (stdlib must be installed, see Installation)make docs
→ generate the c++ source code documentation (Doxygen is required)
Once the configuration step in Compiling is done, use the following to install EARL as well as the stdlib.
cd build
make
sudo make install
make test
To uninstall, simply do sudo make uninstall
.
Syntax highlighting for Emacs, Vim, and VSCode and can be installed by clicking here.
earlmgr
is a script similar to Python’s pip
and can be downloaded here.
Note: earlmgr
is a WIP. USE AT YOUR OWN RISK!
- Functions should be formatted as such:
<return type> <name>(<params>) { body... }
- All indents should be 4 spaces and do not use tabs.
- Macros should be in CAPS. The only exception is for when you want to treat a macro as a function.
- Always put a comment after
#endif
with what it is ending.
struct <NameOfStruct> { ... }
- All struct names must use pascal case
<NameOfStruct>
.
- All
if
,for
,while
etc. should have brackets (the left bracket should be on the same line as the statement). While not required, if a conditional/loop only has one statement, you can ommit the brackets. Just make sure it is on a different line. +
,-
,*
,/
, etc. does not need whitespace, but == should.- Lines have a soft limit of 85 characters.
typedef
‘d types should have_t
appended to it. Example:
typedef int my_type_t;
- All variable, function, and macro names should be
snake_case
. - All file names have a hyphen (‘-‘) to separate words.
- Remove unnecessary trailing whitespace.
- Disable auto-formatters (unless it conforms with the C default style of BSD).
Click here for the EARL Language Reference
EARL uses Doxygen to auto generate documentation for the source code of EARL.
All header files should have doxygen comments explaining what is necessary. Do not put
any in .cpp
files (unless there is no related header for it).
Please read the Doxygen documentation (or at least what is relevant) before documenting the code. At the very least, refer to other files and follow the current way Doxygen comments are written.
If new directories are created and the files need documentation,
edit EARL/src/Doxyfile
under the Configuration options related to the input files
,
the INPUT
switch by adding the directory(s) and file(s) that are needed.
To see the documentation, run make docs
or make all
and open EARL/docs/html/index.html
in a browser.
Click the below link to view the autogenerated documentation after make docs
has been ran.
EARL Development Documentation
- New portable flag to bake the stdlib into the interpeter
flush
intrinsic function.
- New containers in Stdlib
- Reorganized imports.
with
statements.
- New flag
disable-implicit-returns
. - New flag
--oneshot
.
- You can now implicitly return.
unwrap_or
member intrinsic foroption
datatype.
- New intrinsic function
copy
. - Added release script.
- New Colors module.
- New
case
expression.
- Not being able to escape certain sequences in characters.
use
andexec
statements. This allows to import external shell scripts.-e
flag to fail when bash fails.
- OS and MODULE builtin identifiers.
--batch
,-b
flags for running multiple scripts.
- Event listeners.
- Themes in REPL.
- Configuration file.
- CLI flag -I and –include.
- CLI flag -i and –import.
- New REPL command sequence `auto`.
- REPL autocomplete menu now uses a prefix trie.
- Added multiline bash commands
- REPL keywords autocomplete.
- REPL parens count to know when exited suspended eval-state.
- REPL syntax highlighting.
- REPL emacs keybinds.
- Bash literal piping.
@experimental
flag.
- set_flag, unset_flag, new debug flags.
- Updated stdlib-docs-gen.rl to accomodate new doccoments
- Doc Comments to variables, functions, enums, and classes.
- Bash commands
- [MAJOR] Imports now use expression rather than string literals
--to-py
option to convert EARL to Python
- Added cd() to System module
- You can now add aliases to imports.
- New intrinsic
env
. - New module
Script
.
- [MAJOR] Time datatype
- Segfaulting when running EARL with -c and –watch and a parser error occurs.
- floor and ceil functions to math module
- Various optimizations
- [MAJOR] Option of explicit typing.
- [MAJOR] Tuple destructuring in foreach loops.
- Foreach enumerate over dictionaries.
- More functions to the Str stdlib module.
- New unix_cmd function in the System stdlib module.
- Function with `return;` would not actually return from the function.
- -=, /=, and %= giving incorrect values.
- Assert module in the stdlib.
- Builtin Identifiers __FILE__ and __FUNC__.
- [MAJOR] New REPL functionality.
- New repl command :reset that will clear all declared identifiers.
- Levenshtein distance algorithm on function names and misspelled interpreter flags.
- You can now see functions and variables in scope in the repl.
- Intrinsic function ‘warn’
- += operations on strs and lists are now optimized.
- StdLib docs generator.
- Levenshtein distance algorithm for interpreter flags.
- spec_mutate() for str did not copy over the allocated characters.
- You can now mutate classes.
- Added better error message with malformed classes.
- Various segfault bugs.
- @const attribute.
- Variable and function caching.
- List map() member intrinsic
- contains() member intrinsic for lists, tuples, and strs.
- You can now use the ‘this’ keyword in closures inside of classes.
- Power operator
**
.
- Fixed segfaulting on parser errors when hot reloading.
- Fixed the len() unreachable case happening.
- All EARL values now have an appropriate to_cxxstring.
- Greatly simplified __intrinsic_print.
- Better closure printing.
- Intrinsics now report better error messages.
- Fstrings.
- Fixed the bug where foreach loops would always take the value that they are iterating over as a reference.
- Bitwise operators.
- Using .append() on a list no longer always does an unnecessary copy.
- Updated class deep copy to now actually copy over methods.
- Fixed segfault with incorrect function/closure paremeters are provided in evaluate\_function\_parameters\_wrefs.
- Fixed segfault because function\_exists and function\_get for function context not being the same.
- New flag to watch files for changes and perform hot reloading.
- String optimization
- Implemented the
continue
keyword.
- List/str/dictionary/tuple indexing no longer returns the value as a reference by default.
- Strings can now have delimiters again.
- Fixed the bug where dictionaries would end parsing expressions.
- Dictionaries now return none if the value does not exist, and some(V) if it does exist.
- Some recursion optimizations
- Calling a class method that has the same name as a member intrinsic no longer fails.
- std/set.rl now uses an AVL tree instead of a regulary binary search tree.
- MAJOR Added new Dictionary type.
- Added new TypeKW type.
- Unit types now return false in boolean expressions.
- Added new Char module to stdlib
- Added tuple destructuring to allow for multiple variables to be declared in a single
let
statement.
- Classes allowing duplicate member variables.
- Precedence changes to ranges and slices.
- MAJOR Fixed nested for loop bug where the second enumerator would point to the first if set to it.
- Added list slicing
- [MAJOR] Added much better error reporting during runtime (interpreter.cpp).
- Better error messages for the expect_keyword function in parser.
- The minimum cmake version in the README is now up to date with what it actually it.
- Ranges can now be inclusive using the === symbol.
- Fixed the bug when removing or editing a line of code in the REPL that had a bracket.
- MAJOR New build system CMake
- Adjusted minimum CMake version to support Debian
- New name_and_ext function in the OS module.
- Performing str += str caused a segfault because of
char
conversion. - Fixed having excess semicolons segfaulting. They now throw an error.
- MAJOR Fixed array null access that was causing segfaults on MacOS.
- Fixed allowing the creation of duplicate enums of the same name.
- Fixed segfault with invalid getter operation. It now throws an error.
- Added Intrinsic casting functions.
- MAJOR Added a REPL
- Fixed file handler mode type to except multiple types
- The appropriate unit functions now return a unit type instead of null.
- MAJOR New Tuple type
- MAJOR
foreach
loops now take an expression (list/range) as the argument. - MAJOR in
foreach
loops, the enumerator can now have attributes. - MAJOR
<list>.rev()
does not reverse the list in-place anymore. It now produces a new list with the elements reversed. - MAJOR changed syntax for the regular
for
loops.
- Syntax sugar for lists in the form of a range ie [0..10] (range is from 0-9) or [‘a’..’z’].
- Member variables and methods in classes now adhere to the @pub and private system
- Renamed keyword
mod
->module
- Enums
- Float type
- Unary Expressions
- Better output when printing enumerations
- Import depth
- Enum type security
- Better error messages for type mismatchs
- MINOR Fixed segfault bug when creating a float without a left number ie
.34
. - MAJOR Fixed integer+float bug