Version 0.1.0
Gravel is an experimental programming language currently under active development. Its goal is to provide a clean and intuitive syntax while preserving the flexibility and power of low-level programming languages.
As the project is still in its early stages, features and syntax may evolve over time.
Note
Gravel is still in active development. The syntax shown below represents the current design and may change in future releases.
For using files as libraries, use packages, so you will need to use the package name instead of the path.
package: string
If no package defined, couldn't be used for libraries. Naming the package isn't mandatory, but really recommended
To import packages, use a tuple or a single string for importing them.
import "string"
or
import ("string", "stdio", "math", "rand")
There are two ways of defining variables: explicitly and inferenced.
Explicit:
int name = value //or any other type (builtin: int, char, float)
Inferred:
val name := value
You can now define constant variables (as normal ones can't be modified, at the moment, there is no difference at all, though) using const name := val
Create namespaces using namespace name and use the end keyword. (separation: '.')
Instead of defining a lot of small namespaces like this:
namespace rounded_math
val pi := 3
val e := 2
end
You can write, getting the exact same effect:
val rounded_math.pi := 3
val rounded_math.e := 2
Use the end keyword, and use the following syntax: whatever cond. For for, use: for i in n, which iterates i from 0 to n-1, but classic syntax will also be accepted for int i=0; i<10; i++ or as wanted.
Traditional for-loop:
for int i=0; i<10; i++
std.out.print("hello, but tenfold!")
end
Modern for-loop:
for i in 5
std.out.print(i)
end
While loops:
val qux := 10
while qux < 10
qux += 1
end
Conditionals:
if cond
...
elseif cond
...
else
...
endUse this syntax:
repeat 10
scho('a')
end
output:
aaaaaaaaaa
Use the end keyword, and use the reserved word fun. Define return type after args (optional).
fun Main() char
As everywhere, use end to declare when the class ends. if you put type at the end of class name:, you are saying that this class will act as a type, instead of being a constructor for organization and creating objects.
With type:
class string: type
extl char[] text
impl int len
fun __USE__()
text = extl
len = sizeof(text)
end
end
Explanation: extl and impl are from type classes, and extl is the external value (in string name = "hi", extl would be "hi"), and impl means implicit: can't be changed, but can be accessed by other than the class itself. It also means it's calculated by the class automatically.
The __USE__(): function is triggered when defined a value with the class type. This is ONLY for type classes.
Pointers use the default way for reference-dereference (& and *). To create a pointer it's also the C way.
int* name = &reference
I will make a lib with at least these two functions: (For single character output, use scho)
std.out.print(char[])
and
std.in.ask(&ref, char[])
Gravel features a handful of methods for primitives. Integer methods are still a work in progress.
String Methods:
- upcase -> uppercase every character of a string
- downcase -> lowercase every character of a string
- split() -> separate each value in a string by the given operator. if none, split by spaces. Returns an array of each extracted value.
- bite -> removes the newline from std.in.ask
- to_integer -> turns a string like '1' into the integer 1.
Array Methods:
- prepend -> add a value to the front of an array and shift every other value
- push -> add a value to the end of an array
- erase/clear -> removes all values
- length/size -> the amount of values
- purity -> returns a boolean of true if all values are truthy; returns false if there is a falsy value.
- divide -> argue an integer; it will split the array at the index of the given integer:
['foobar', 'baz', 'qux'].divide(2) // => ['foobar', 'baz']Note that it will discard every value after the given index.
Dictionary Methods:
- exists-> checks if the dictionary has a key matching the argument -- see 'alive' below.
- alive -> checks if the dictionary has a value matching the argument
- count -> how many keys a dictionary has
- brothers/siblings -> returns an integer of how many keys have a value that is truthy.
- family -> returns a boolean if any key is missing a value or if any key is falsy
- purify -> assigns undefined/undef to every value; preserves keys. Optionally, this could return an array of every removed value.
Right now, this is the current development of every feature:
| Feature | Status |
|---|---|
| Tokenizer | Working |
| AST | Working |
| Parser | Working |
| LLVM converter | Working |
| Variables, types and classes | 1/3 |
| Functions, namespaces, if, while, for, repeat | 5/6 |
| Packages, pointers, import and basic packages | NOT STARTED |
To propose or vote on small syntax changes, please go to discussions.
This is the Gravel launcher. This launcher goal is to provide basic CLI tools to run your Gravel code.
Use the following pipeline for executing a file.
gravel run main.grv dependencies path space separated.(Maybe we will add a file for tracking dependencies, like Cargo.toml but for Gravel)
To run the resulting output.ll, do the following:
IF WINDOWS: you can use:
./argc winll llvm\llvm.exebut it will run automatically, so you can use this for executing othre output.ll.
ELSE: you can use: (make sure to have llvmlite installed)
./argc pyll llvm\llvm.pyit also runs automatically, but you need to do pip install llvmlite.
New version of the benchmark: it now repeats 30 times!
This repo includes a bench.grv file with 33576 tokens. You can execute it to test the speed. I got 0.379000 s, let's see what you get running ./main run main.grv -wE (change ./main for the actual executable).
This time includes only:
- Detection of argument "run" and getting the path
- Opening the file and compiling it
- Write the
.llfile
-wE: Shows various information, as time and token count. (only time used compiling to LLVM, not the LLVM execution itself)
- Constant Folding: Numerical operations including numbers (and future constant varibles) are done during compilation.
- Namespace Flattening: Namespace are flattened instead of saving complex tree structures.
Currently available contents
- scho('A') / scho(intvar)
- int intvar = 65 / val intvar := 65
- namespace name ... end / name.getthis
- val namespace.gettheanother := 65
- Line comments // and block comments /* */
- If elseif else
- While and for loops (with comparison, increment/decrement and compound-assignment operators)
- Int args and int/void return functions
- Reassing varibles
The changelog idea is from BeknYTprogamador
- Project initialization and first commit
- Started development on the compiler (Day 1: Tokenizer)
- Added initial README file with small fixes
- Continued tokenizer development
- Removed accidental files
- Updated README with new
gravelcommand usage details - Clarified
extlandimpldefinitions in the README
- Finished tokenizer development and started AST (Abstract Syntax Tree)
- Finished AST development and started the parser
- Updated project status section in the README
- Prepared AST and parser for bug fixes
- Fixed bugs, debugged, and added
clang.exefor future use
- Fixed various bugs
- Started LLVM IR translation and noted initial bugs
- Started mapping variables to LLVM IR
- Added
libsfolder featuring standard packages written in Gravel - Implemented single-character output experimentation in LLVM
- Continued LLVM IR transpilation work and resolved active bugs
- Updated the README
- Codebase fixes and general maintenance
- Code debugging and system fixes
- Fixed the random library implementation
- Fixed spelling errors and enhanced terminology clarity in the README
- Implemented LLVM transpilation updates and performed debugging
- Removed forced indentation requirements
- Added notes to the README regarding the future Gravel dependency tracking file
- Released the first working version of the project
- Updated project status and removed temporary notes from the README
- Added compilation details to the update section of the README
- Achieved successful file compilation and executed the first "Hello, World!"
- Updated the README with bug notes and future development plans
- General code fixes
- Added error management logic and variable inference capabilities for
INT - General code tweaks and performance optimization
- Updated project status in the README
- Deleted the temporary
main.grvfile
- Added full support and implementation for Namespaces
- Updated the README with the new namespace syntax and declaration capabilities
- Revised progress status in the README
- Prepared infrastructure for Error Explaining 2.0
- Updated README with changelog
- Optimized with constant folding
- Added new flag (
-wE) for showing time spent compiling
- Added token count when using
-wE
- Updated libs with new syntax
- Added
bench.grvto test its speed - Added Actions for Windows, Ubuntu, MacOS and FreeBSD
- Add
repeatfunctionality
- Add constant definition
- Upgrade README (PR)
- Comment support (PR)
- Create examples folder (PR)
- Add newline (
\n) support - Add AI-POLICY.md
- Add methods for primitives ideas on readme (PR)
- Implement comment blocks
- Bug fixes
- Add explicit int variables
- Update "Update" section
- Add if, elseif, else
- Implement noarg & no return function definition
- These functions are now callable
- Add DESIGN.md
- Fix spelling in readme and design (PR)
- Add VScode extension
- Change syntax: no colons and -> type to only type
- Fix AST example at DESIGN.md
- Functions can return ints now
- Updated vscode extension
- Fixed libaries code
- Added CONTRIBUTING.md
- Added modulo operation (PR)
- Names can contain '_'
- Fix ifs
- Change main.grv to a factorial function
- Add variable reassing
- Add and improve examples
- If reassigning an undefined variable, an error is thrown (PR)
- If file doesn't exist, error is thrown (PR)
- Add int arguments
- Add tests
- Add LLVM IR execution
- Add basic EBNF grammar explanation
- Implemented some commits from skeeto's fork:
b283d3c: Fix integer overflow when folding literalsa055ec6: Fix buffer overflow when names too longa0b2132: Fix unclosed /* comments4b1fc85: Fix null or empty dereference
- Fix Python test
- Bug fix
- Add sanitizers.yml workflow
- Fix possible memory error
- Improve Python LLVM executor
- Use Python always to execute LLVM
- Fix sanitizer warnings
- Add
whileandforloops (classicfor int i=0; i<10; i++and modernfor i in n) (PR) - Add comparison operators (
<,>,<=,>=,!=) (PR) - Add increment/decrement (
i++,i--) and compound assignment (+=,-=,*=,/=,%=) operators (PR) - Fix tokenizer never emitting
,, enabling multi-argument functions and calls (PR) - Update grammar documentation and add loop tests (PR)
