Basically, the architecture is splitted into 5 layers
- parsing layer
- symbol extraction layer
- type check layer
- IR analysis layer
- production layer
Each layer take data in input and either
- add more information on input data
- transform input data into another format
Those layers are drived by one class : SerialCompilerProcessorImpl (net.nosica.compiler.application.SerialCompilerProcessorImpl). The role of SerialCompilerProcessorImpl is to bootstrap the compilation process by compiling some native classes needed for compilation (like None, String, String[] ...) and the main class passed as parameter to the compiler.
Parsing layer
Location: net.nosica.parser
Input: Nosica source file
Output: Decorated parsed tree
All nodes of the parsed tree are located at net.nosica.parser.node
Symbol extraction layer
Location: net.nosica.symbol
Input: Decorated parsed tree
Output: Symbol table
The symbol table is composed of :
- SymbolEnvironment : contains all GenericType (net.nosica.application.SymbolEnvironment)
- GenericType : the symbol representation of a parsed Nosica type. It contains GenericMethod and Field
- GenericMethod : the symbol representation of a parsed Nosica method.
- Field : the symbol representation of a parser Nosica field
At symbol stage, we cannot know if a type is generic or not. Therefore, we denote this fact that stating that all types are possibly generic. Therefore the name GenericType and GenericMethod. Field cannot be generic. Never. Therefore they are simply called Field. Not GenericField. We cannot know a type is generic or not because types like MyType<int32> are in fact not generic as they are fully resolved. The problem is that, at this stage, we cannot know if int32 is a generic parameter (like T) or if it's a fully resolved type name (like net.nosica.lang.int32).
Type check layer
Location: net.nosica.compiler.typecheck
Input: Decorated parsed tree
Output : IR (Intermediate Representation)
The type check layer visits all nodes of a decorated parsed tree and reports errors as it detects them. On the flow it translate the Nosica source code's complex tree in an IR. IR nodes are located in net.nosica.compiler.intermediate
IR Analysis layer
Location: net.nosica.compiler.analysis
Input : IR
Output : modified IR or/and more information on IR for better code production
Production layer
Location: net.nosica.compiler.production
Input : IR
Output : target source code
Currently we only compil to c source code.
Type loading, genericity solving
There is a special class : net.nosica.compiler.application.TypeLoaderImpl whose role is to create a fully resolved Type suitable for type checking. Here's how it works :
- It receives a TypeName in input
- It looks if it already knows this type in the Symbol table (SymbolEnvironment)
- If not, it tries to load it using the FileLoader (net.nosica.application.FileLoader), the parser and the symbol extraction
- It also loads all dependencies of this type
- At this point, it has to make a match between a TypeName and a set of GenericType
- If there is a match, it uses the GenericitySolver (net.nosica.compiler.application.GenericitySolver) to transform the GenericType into a fully resolved type (net.nosica.compiler.typechecker.Type)
- It then stores the resolved types in the TypeEnvironment (net.nosica.compiler.application.TypeEnvironment)
No comments yet