# Validating the AST
So far we've defined the language in terms of its grammar. Especially for expressions we're still dealing with ambiguity in the interpretation of raw text, and with certain statements or expressions that are invalid in a particular context. We'll deal with these in several phases in this section. Note that some conditions for validity are delayed until the section on typing, as it is more appropriate to introduce those restrictions there.
## Scoping and Naming Rules
Without any further constraints one may define variables or types with the same name. So we introduce rules for the various identifiers that are found within a program.
Within the root of a module we are at the module scope. It's only parent is the global scope (whose contents we'll introduce later). The identifiers of type and procedure declarations within the module may not conflict with one another, or with any of the identifiers in the global scope.
Secondly, imports introduce identifiers into the module scope. Identifiers of procedures and types imported into a module may not conflict with one another, the global scope (which is implicitly already satisfied, unless the import becomes aliased), or the types defined within a module. In case an import produces an alias for a particular type or procedure, then that is the identifier that may not conflict.
Whenever we're parsing a procedure (function or component), we enter a new scope whose parent is the module scope. Block statements implicitly introduce a new child scope. Any defined variable's identifier will be added to the scope it is in, and may not conflict with another identifier in the same scope or parent scopes.
**note**: Look up if I made mistakes with labels.
Various other groups of identifiers in the program may not conflict among themselves. These are:
- The polymorphic variables of type or procedure definitions.
- The fields names of a struct.
- The variants of an enum.
- The identifiers of variants of a union (even though they might have had a different number of embedded values).
## Polymorphic Argument Rules
Types and procedures may be defined using polymorphic variables. Whenever we use these types to construct literals, or use functions to perform calls, we may specify these as polymorphic arguments. One has the choice of:
1. Specifying all of the polymorphic arguments. Note that one may still allow for type inference by using the `auto` type in the place of the polymorphic argument.
2. Specifying none of the polymorphic arguments, in this the compiler must assume that all of the polymorphic arguments are to be inferred (i.e. as if the programmer had written `auto` for each of the polymorphic arguments).
Any other case should be a compile-time error.
**note**: At the moment polymorphism in the language is rather underpowered until a reasonable and simple scheme for constraining them can be found. At the moment one can only specify one of the builtin types or struct/enum/union types of polymorphic arguments. Furthermore functions and procedures defined with polymorphic variables may not construct literals by using them.
## Expression Rules
### Assignment
Assignment expressions may only be placed at the statement level. That is to say: viewing a series of expressions as a tree, where each node has a parent expression or a parent statement (e.g. the test expression of an if-statement), then assignment expressions may only have the expression-statement as a parent.
The left hand side of an assignment expression should be assignable. An expression is assignable if it is:
- An indexing expression with an assignable subject expression.
- A slicing expression with an assignable subject expression.
- A select expression with an assignable subject expression.
- A variable expression.
### Literals
An enum literal is valid if its `TypeRef` points to an enum declaration (either directly, or through a potentially aliased import) and the subsequent identifier is a variant declared in the type definition.
A union literal is valid if its `TypeRef` points (indirectly) to a union declaration, the subsequent identifier is a variant in the type definition, and if (where applicable) the number of embedded expressions matches the number of embedded types in the variant's definitions.
A struct literal is valid if its `TypeRef` points (indirectly) to a struct declaration, and it provides an expression to initialize all of the struct's fields, and only initializes each field once.
For all of these literals the rules for polymorphic arguments apply: if the type specifies polymorphic arguments, then all of them have to be specified or none of them have to be specified (for implicit type inference).
### Binding
A binding expression itself is only valid if it is nested in the expression tree under no expressions, or only binary expressions. The chain of parents must terminate at an if-statement or while-statements test expression. As a result, binding expressions may not be nested in one another.
A binding expression's left hand side is valid if it is a binding variable, or if it is a literal that may contain a binding variable. A binding variable is a variable that has not yet been declared using a `StmtLocalMem`. Such a variable will then be implicitly be declared at the binding location, and usable within the scope of the if-statement's then-block, or the while-statement's loop body. The same scoping rules apply to that scope: so binding variables may not be declared twice, nor may conflict to any variables declared in the scope or it's parents.
Furthermore, the parent of a binding variable may only be some kind of literal expression, or the left hand side of the binding expression itself.
### Function Calls
The `TypeRef` for a function call should resolve to either a builtin function, or a user-defined function. Function calls follow the rules for polymorphic arguments as outlined above. Furthermore the number of expressions given as arguments to the function should match the number of arguments in the definition of the function.
### Component "Calls"
The `TypeRef` for a component call should resolve to either a builtin component, or a user-defined component. Component calls, like function calls, must following the rules for polymorphic arguments and the arguments to the components themselves. Furthermore component "call" expressions may only be placed with a `StmtNew` as parent. That is to say: one doesn't really call components, instead one instantiates them.
## Builtin Procedures