-
Notifications
You must be signed in to change notification settings - Fork 64
Contributor Guide
The purpose of this document is to help new contributors to get started on the project. We do this by providing a high level overview of the project goals, norms and architecture.
The project also aims to develop a fully featured language server based on a reusable VHDL parsing & analysis library. The VHDL parsing & analysis library is intended to be able to be re-used by other open source projects that also need such functionally. The idea is that the investment in parsing & analyzing VHDL can be shared by many projects.
The choice of having the language server be the driving requirement behind the parsing & analysis library is the assumption that a language server is the most difficult requirement. A language server requires quick incremental re-analysis as well as robust handling of syntactically incorrect code as it is being edited. A fast and full featured language server also provides a lot of value to the users of VHDL.
The main focus is VHDL-2008 and above as it is the most practically interesting. User who wants to stick to 93 subset and get errors for use of newer VHDL features are not a priority. Such features can be added if the interest exists as a linting pass.
-
vhdl_lang
- VHDL parsing & analysis library -
vhdl_ls
- VHDL language server
- Follow the VHDL LRM and aim to be 100% compliant.
- Do not assume your mental model of VHDL is correct without reading the LRM.
- Starting work without studying the LRM can lead to architectural dead ends.
- All features must have good quality unit test proving they continue to work as intended.
- The test should be nice to read and not be a burden to maintain but also cover the functionality.
The main driver for the vhdl_lang
architecture is to be a good fit for a language server. This poses a few driving requirements:
- The entire VHDL syntax-tree should be in memory and be query-able.
- Syntax errors occur while typing new code and must be recoverable.
- A VHDL code change should only require a small update of the in-memory AST.
Also to take advantage of modern multi core processors parallel processing should be performed.
The structure of vhdl_lang
is divided into of a few distinct concerns;
Relevant sub-modules: data
, ast
, syntax
The first step is to parse the VHDL code into a syntax tree representing the lexical structure of the language. The syntax tree contains source location information that allows the mapping of every element to its original source position. Parsing can be done in parallel at the granularity of individual files.
-- Is foo an array of a function, at parsing time we cannot know
value := foo(1);
Relevant sub-modules: analysis
The analysis step involves resolving all symbols and their type.
-- Resolving symbol std_logic is required to know it refers to the type defined in package ieee.std_logic_1164;
signal foo : std_logic;
-- Resolving subprogram calls may involve knowing the type of the arguments
function foo(value : boolean) return boolean;
function foo(value : integer) return boolean;
-- ...
-- Which symbol does foo refer to?
value := foo(1);
Analysis must consider the visible region of symbols. A symbol defined in a process
is only visible inside that process and only after it was defined.
Such regions form a tree structure. The LRM talks about declarative regions.
We aim to perform the analysis in a single pass over the syntax tree resolving all symbols and types in the process. During analysis a tree like structure of declarative regions are constructed. This structure is separate from the syntax tree. The syntax tree elements only contain blank references that are filled in with references to the declarative region data structure.
Analysis cannot be fully parallelized since VHDL design units form a tree-like dependency graph that must be analyzed in the tree-order. As long as the dependency order is respected several design units can be analyzed in parallel. To support efficient parallel analysis a design unit is only exclusively locked for writing when analyzed by a single thread but when analyzing dependent design units they can share a read-only access to the already analyzed design unit.
Relevant sub-modules: ast::search
Querying involves searching the in-memory data structures generated by parsing and analysis. Typical queries are;
- Find definition: what symbol is at this cursor position and where is it defined.
- Find all references: the list of all references to the symbol under the cursor.
Efficient incremental analysis on code changes is performed by first re-parsing only the file that changed. Based on the design units inside this file and the knowledge of the dependency graph all dependent design units are re-analyzed with as much parallelism as the dependency graph allow. This works well as even for large projects a single file change will not affect most of the dependency tree.
Parsing is very complete & mature and can handle practically all of VHDL-2008. Analysis is able to resolve non-overloaded symbols. Overloaded symbols require type-signature checking which is not completed. The main area of work is to complete type checking such that overloaded symbols can be resolved which takes the language server to the next level.