I tried to make the code of the compiler and vlib as simple and readable as possible. One of V's goals is to be open to developers with different levels of experience in compiler development. Compilers don't need to be black boxes full of magic that only few people understand.
The V compiler is modular, and can be used by other applications. It is located
The most important and useful command to remember when working on the V compiler
It rebuilds the V compiler.
Be careful, if you introduce a breaking change and rebuild V, you will no longer be able to use V to build itself. So it's a good idea to make a backup copy of a working compiler executable.
But don't worry, you can always simply run
make.bat), it will
download the C version of the compiler and rebuild it from scratch.
The architecture of the compiler is very simple and has three distinct steps:
Parse/generate AST (
v.parser) => Check types (
The main files are:
cmd/v/v.vThe entry point.
vlib/v/scanner The scanner's job is to parse a list of characters and convert
them to tokens.
vlib/v/token This is simply a list of all tokens, their string values, and a
couple of helper functions.
vlib/v/parser The parser. It converts a list of tokens into an AST.
In V, objects can be used before declaration, so unknown types are marked as
unresolved. They are resolved later in the type checker.
vlib/v/table V creates one table object that is shared by all parsers. It
contains all types, consts, and functions, as well as several helpers to search
for objects by name, register new objects, modify types' fields, etc.
vlib/v/checker Type checker and resolver. It processes the AST and makes sure
the types are correct. Unresolved types are resolved, type information is added
to the AST.
vlib/v/gen/c C backend. It simply walks the AST and generates C code that can be
compiled with Clang, GCC, Visual Studio, and TCC.
executed on the browser or in NodeJS/Deno.
vlib/v/gen/c/json.v defines the json code generation. This file will be removed once V
supports comptime code generation, and it will be possible to do this using the
vlib/v/gen/native is the directory with all the machine code generation logic. It
defines a set of functions that translate assembly instructions to machine code
and build the binary from scratch byte by byte. It manually builds all headers,
segments, sections, symtable, relocations, etc. Right now it only has basic
support of the native platform (ELF, MACHO format).
The rest of the directories are vlib modules:
builtin/ (strings, arrays,
os/, etc. Their documentation is pretty clear.
(provided by @spytheman)
(If you don't already have a GitHub account, please create one. Your GitHub username will be referred to later as 'YOUR_GITHUB_USERNAME'. Change it accordingly in the steps below.)
Fork https://github.com/vlang/v using GitHub's interface to your own account.
Let's say that the forked repository is at
Clone the main v repository https://github.com/vlang/v to a local folder on
your computer, say named nv/ (
git clone https://github.com/vlang/v nv)
git remote add pullrequest https://github.com/YOUR_GITHUB_USERNAME/v
NB: the remote named
pullrequest should point to YOUR own forked repo, not the
main v repository! After this, your local cloned repository is prepared for
making pullrequests, and you can just do normal git operations such as:
git status and so on.
When finished with a feature/bugfix/change, you can:
git checkout -b fix_alabala
v fmt -w YOUR_MODIFIED_FILESbefore committing
git push pullrequest # (NOTE: the
pullrequest remote was setup on step 4)
On GitHub's web interface, go to: https://github.com/vlang/v/pulls
Here the UI shows a dialog with a button to make a new pull request based on the new pushed branch. (Example dialog: https://url4e.com/gyazo/images/364edc04.png)
After making your pullrequest (aka, PR), you can continue to work on the
fix_alabala ... just do again
git push pullrequest when you have more
If there are merge conflicts, or a branch lags too much behind V's master, you can do the following:
git pull --rebase origin master# solve conflicts and do
git rebase --continue
git push pullrequest -f# this will overwrite your current remote branch with the updated version of your changes.
The point of doing the above steps, is to never directly push to the main V
repository, only to your own fork. Since your local
master branch tracks the
main V repository's master, then
git checkout master, as well as
git pull --rebase origin master will continue to work as expected
(these are actually used by
v up) and git can always do it cleanly.
Git is very flexible, so there are other ways to accomplish the same thing. See the GitHub flow, for more information.
You can download the
hub tool from https://hub.github.com/ . Using
hub, you will not need to go through the (sometimes) slow website
to make PRs. Most remote operations can be done through the
NB: You still need to have a GitHub account.
(steps 1..3 need to be done just once):
hub clone vlang/v my_v
hub fork --remote-name pullrequest
git checkout -b my_cool_feature # Step 4 is better done once per each new
feature/bugfix that you make.
git commit -am "math: add a new function copysign"
You can test locally whether your changes have not broken something by
v test-all. See
TESTS.md for more details.
git push pullrequest
(so that your changes can be merged to the main V repository)
Optionally, you can track the status of your PR CI tests with:
hub ci-status --verbose
If everything is OK, after 5-10 minutes, the CI tests should pass for
all platforms. If not, visit the URLs for the failing CI jobs, see
which tests have failed and then fix them by making more changes. Just use
git push pullrequest to publish your changes. The CI tests will
run with your updated code. Use
hub ci-status --verbose to monitor
V allows you to pass custom flags using
-d my_flag that can then be checked
at compile time (see the documentation about
There are numerous flags that can be passed when building the compiler
v self or when creating a copy of the compiler, that will help
you when debugging.
Beware that the flags must be passed when building the compiler,
not the program, so do for example:
v -d time_parsing cmd/v or
v -d trace_checker self.
Some flags can make the compiler very verbose, so it is recommended
to create a copy of the compiler rather than replacing it with
||Prints debug information during the scanning phase|
||Prints automatically generated V code during the scanning phase|
||Prints generated interfaces during C generation|
||Prints debug information when checking that a type implements in interface|
||Prints vweb compiled HTML files|
||Prints the time spent checking files and other related information|
||Prints the time spent parsing files and other related information|
||Prints details about how/when -autofree puts free() calls|
||Prints details about
||Prints options passed down to the C compiler|
||Prints details about the statements being checked|
||Prints strings written to the generated C file. Beware, this flag is very verbose|
||Prints details about parsed statements and expressions|
||Prints details about built thirdparty obj files|
||Prints details when -usecache is used|
||Prints details when $embed_file is used|
||Embed only the metadata for the file(s) with