compiler/sem/sem

  Source   Edit

This module implements the instantiation of generic procs. included from sem.nimThis module implements semantic checking for calls. included from sem.nimthis module does the semantic checking of type declarations included from sem.nimThe current implementation of templates might not yet conform to the description that follows.

Template Basics

Given a basic template as follows: ..code:

template identity(arg: untyped): untyped =
  arg

The template's output type is untyped, meaning the body (arg) is treated as an untyped AST fragment, that substitution of parameters will evaluate per the rules of untyped templates, and finally evaluation and insertion of the template at the callsite will be hygeinic. The template parameter arg will be captured as untyped, meaning no attempt will be made to semantically analyse the parameter prior to substitution.

Template Taxonomy

There are at least four types of templates across two categories:

  • AST templates:
    • untyped
      • dirty a non-hygienic sub-variant
    • typed
  • expression templates (all types that are not untyped or typed)

Substitution Positions

Templates are ultimately AST level constructs regardless of output type, they must be valid syntax. There are two types of positions in a template body, one is definition and the other is usage. A definition is any position where the grammar construct is intended to introduce a new symbol, i.e.: the name of a routine, including its parameters; names of variables (const, let, var), and so on. All other sites are usage sites, where a symbol referring to a "chunk" of AST might be used.

This is a draft of subsitution rules:

  • untyped template bodies accept untyped params in definition or usage positions; and all other params are usage only
  • typed template bodies accept untyped params in definition or usage positions; and all other params are usage only
  • non-ast template bodies only allow subsitutions within usage positions

This implements the first pass over the generic body; it resolves some symbols. Thus for generics there is a two-phase symbol lookup.

A two-phase lookup as today is templates and not generics, AKA mistake.

A problem is that it cannot be detected if the symbol is introduced as in var x = ... or used because macros/templates can hide this! So we have to eval templates/macros right here so that symbol lookup can be accurate.

included from sem.nim
this module does the semantic checking of statements
included from sem.nim
This module does the semantic transformation of the fields* iterators.
included from semstmts.nim
this module does the semantic checking for expressions included from sem.nimThis module implements Nim's object construction rules.

Future Considerations/Improvements:

  • The return nil pattern leads to a lot of boilerplate, most of this is for PNodes which can be converted to use nkEmpty and/or optional.
included from sem.nim

Consts

semPass = (open: myOpen, process: myProcess, close: myClose, isFrontend: true)
  Source   Edit
tyGenericLike = {tyGenericInvocation, tyGenericInst, tyArray, tySet, tySequence,
                 tyOpenArray, tyUserTypeClassInst..tyCompositeTypeClass}
  Source   Edit
tyMagicGenerics = {tySet, tySequence, tyArray, tyOpenArray}
  Source   Edit
tyUserDefinedGenerics = {tyGenericInst, tyGenericInvocation, tyUserTypeClassInst}
  Source   Edit

Procs

proc commonType(c: PContext; x, y: PType): PType {.
    ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
  Source   Edit
proc commonType(c: PContext; x: PType; y: PNode): PType {.
    ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
  Source   Edit
func defNameErrorNodeAllowsSymUpdate(n: PNode): bool {.inline, ...raises: [],
    tags: [].}
true if n is an nkError of kind adSemSymNameSym and the error is minor enough to allow the recovery sym to be updated. Used to see if progress is allowed inspite of errors.   Source   Edit
func getDefNameSymOrRecover(n: PNode): PSym {.inline, ...raises: [], tags: [].}
extracts the symbol from n, which must be an nkSym or nkError with diagnostic kind of adSemDefNameSym. If n is an error, a recovery symbol is extracted, allowing progress to be made.   Source   Edit
proc instGenericConvertersArg(c: PContext; a: PNode; x: TCandidate) {.
    ...raises: [Exception, ERecoverableError, KeyError, ValueError],
    tags: [RootEffect, ReadDirEffect, ReadIOEffect, ReadEnvEffect, TimeEffect].}
  Source   Edit
proc instGenericConvertersSons(c: PContext; n: PNode; x: TCandidate) {.
    ...raises: [Exception, ERecoverableError, KeyError, ValueError],
    tags: [RootEffect, ReadDirEffect, ReadIOEffect, ReadEnvEffect, TimeEffect].}
  Source   Edit
proc maybeResemArgs(c: PContext; n: PNode; startIdx: int = 1): seq[PNode] {.
    ...raises: [Exception], tags: [RootEffect].}
  Source   Edit
proc newSymGNode(kind: TSymKind; n: PNode; c: PContext): PNode {....raises: [],
    tags: [].}

like newSymS, but considers gensym'ed symbols, analyses n producing a canonical symbol node (nkSym), or if unsuccessful an nkError with an adSemDefNameSym diagnostic.

Symbol canonicalization is is as follows:

  1. nkSym -> match kind (or skTemp) and updates the sym owner to the
    current context (gensym specific)
  2. nkIdentKinds -> instantiate a symbol considering quoted identifiers
  3. nkError -> simply returns the same error
  4. other kinds -> new error
  Source   Edit
proc toLiterals(vals: IntSet; t: PType): seq[PNode] {....raises: [], tags: [].}
  Source   Edit

Templates

template commonTypeBegin(): PType
  Source   Edit