Skip to content
This repository has been archived by the owner on Apr 13, 2019. It is now read-only.

schema language

Konstantin Sobolev edited this page Jun 10, 2016 · 29 revisions

This is a draft page filled as we go with the language implementation

#Imports There are two kinds of imports: namespace imports and single type imports.

Single type import makes one single type from another package available:

import foo.bar.Baz

record R {
  myField: Baz
}

Importing types with the same short name from different namespaces is not allowed:

import foo.bar.Baz
import qux.Baz // clash!

Namespace import brings given namespace into scope, so that namespace prefix can be omitted:

import foo.bar

record R {
  myField: bar.Baz
}

Importing namespaces with the same last segment is not allowed:

import foo.bar
import qux.bar // clash!

Standard imports

The following imports are always implicitly present:

import epigraph.String
import epigraph.Integer
import epigraph.Long
import epigraph.Double
import epigraph.Boolean

See [References implementation](References implementation) for more details.

Reference resolution algorithm

Resolution algorithm works by first building a set of namespace prefixes to search plus a suffix to append to them. These two data structures are later used for actual reference resolution and for autocompletion (in case of IDEA plugin).

For example if resulting prefixes are p1.p2 and p3.p4 and suffix is p5.P then p1.p2.p5.P and p3.p4.p5.P fully-qualified names will be the final resolution candidates.

Resolution of reference R depends on if it's a sequence of fragments n1.n2...T or just one fragment T.

If R is just a single fragment like Baz, then namespace prefix list consists of:

  • explicit imports such that their last segment is R, with last segment removed
  • implicit (standard) imports ending with R, for example epigraph.R, with last segment removed (i.e. currently this is just epigraph)
  • current namespace

Suffix is R.

If R contains multiple fragments starting with n1, then prefix list is:

  • explicit such that their last segment is n1, with last segment removed
  • implicit imports ending with n1, with last segment removed
  • empty (root) namespace

Suffix is R.

Resolution procedure then goes over all prefixes in the list (order matters!), appends suffix to each of them and checks if resulting FQN is an actual type name.

Autocompletion

Same data structures are used by IDEA plugin when doing references autocompletion. Given prefixes list and a suffix it has to build a list of valid completion options. Tricky part is that last segment of user's input always contains an invalid token, for instance if user input R is foo.Ba, then last segment should not be taken into account, only foo is a meaningful part.

If R has more than one segment (with last segment being an invalid token):

  • remove last segment (illegal) from suffix, lets call result 'suffix prefix'
  • take all namespaces of the prefix list, append suffix prefix to them
  • find all types and namespaces inside them

If R is only one (invalid) segment, then prefix list most probably contains nothing but the current namespace, so it's not of much use. Completion options have to be calculated from scratch:

  • for all imports (including standard imports) that point to specific types (and not to namespaces): add short type names
  • all types from standard imports
  • all top-level namespaces
  • all short type names from the current namespace

Inheritance

Type A inherits type B if they are of the same kind and one of the following is true:

  • A extends B
  • B supplements A
  • A is a member of a vartype V and B supplements V
  • A inherits T, and T inherits B (transitivity)

Polymorphic types

Abstract and final type members

Clone this wiki locally