It is important that you run Eclipse 3.7 with an unstable built of Spoofax. All other combinations are likely not to work. Before you start this assignment, you need to [[https://www.dropbox.com/s/afaz26obl0n2ogp/update.zip][update]] the following files in your project: * assignment1/MiniJava.tbl * lib/nbl-library.custom * trans/minijava.str ---++ Name Binding Spoofax' new Name Binding Language (NBL) is a declarative metalanguage for the specification of name bindings in terms of namespaces, definition sites, use sites, and scoping rules. ---+++ Namespaces In NBL, a namespace is a collection of names and is not necessarily connected to a specific language concept. Different concepts can contribute names to a single namespace. For example, in !MiniJava variables and parameters contribute to the same namespace. Namespaces are declared in a =namespace= section. module names imports assignment1/MiniJava namespaces Class You can copy this content into a file =trans/name.nd=. Next, you should extend the =namespace= section with all namespaces of !MiniJava. ---+++ Definition and Use Sites Once you defined namespaces, you can define name bindings with rules of the form =pattern : clause*=, where =pattern= is a term pattern (like in rewrite rules) and =clause*= is a list of name binding declarations about the language construct that matches with pattern. For example, the following rule declares definition sites for class names: rules Class(c, _, _, _): defines Class c Use sites which refer to definition sites of names can be declared similarly. For example, the following rule declares use sites of class names: Parent(c): refers to Class c Identify definition and use sites of names in !MiniJava and define the corresponding rules. ---+++ Editor Integration When you save =trans/names.nd=, Spoofax generates automatically a file =trans/names.str=. This file contains Stratego code implementing name analysis based on the rules you provided. To use this implementation, you should import it into =trans/minijava.str=. When you open a !MiniJava program and inspect its analysed abstract syntax, you will find definition and use sites of names annotated with URIs. For example, =Class("c", ...)= will become =Class("c"{[Class(), c]}, ...)=. In =trans/minijava.str= you can also find boilerplate code for reference resolution (=editor-resolve=) and code completion (=editor-complete=). You can register these strategies in as reference resolver in =editor/MiniJava-References.esv= and completion proposer in =editor/MiniJava-Completions.esv=. After a build, you can try these editor services in a !MiniJava editor. ---+++ Scopes In the current state, all names are globally visible in your project. Thus, you can refer to classes in other !MiniJava programs, which reside in the same Eclipse project. Scopes restrict the visibility of definition sites. For example, a class scopes fields that are not visible from outside the class. This can be specified in NBL by extending the rule for classes with a =scopes= clause: Class(c, _, _, _): defines Class c scopes Field Scopes can be nested and name resolution typically looks for definition sites from inner to outer scopes. As in the class example, scopes are often also definition sites. However, this is not a requirement. For example, a program has no name, but scopes its classes: Program(_, _): scopes Class Extend your name binding rules with =scopes= clauses to scope all definition sites. ---++ Name Checking Similar to type checking, you can realise name checking in terms of constraints, which are implemented as rewrite rules. ---+++ The Index Spoofax stores all definitions and references in an in-memory data structure called the index. By collecting all this summary information about files in a project together, it ensures fast access to global information. The index is updated automatically with changes to the file system (e.g., files being deleted or removed) and is persisted as Eclipse exits. All entries in the index have a URI. Index entries can be represented as terms and accessed by an API. For example, =Def([Class(),"c", Anon("12")]) is a definition entry for a class. Internally, index entries are stored in tables for efficient random access. They also contain meta-data such as the file name and line number of the definition. With this meta-data, Spoofax can provide editor services such as reference resolving. ---+++ Naming Constraints You can use the index API to detect duplicate definitions, missing definitions, and unused definitions: constraint-error: Class(c, _, _, _) -> (c, $[Multiple declarations for class [c]]) where [_, _|_] := c constraint-error: Parent(c) -> (c, $[Class [c] is not defined]) where c constraint-warning: Class(c, _, _, _) -> (c, $[Unused class [c]]) where c ---++ Interaction with Type Analysis ---+++ Types of Definition Sites Spoofax can also store type information about the definition sites of names in the index. For example, to determine the type of variable references, Spoofax needs to store the type of the corresponding declarations. Consider the following name binding rules which also involve type information: Var(t, v): defines Variable v of type t Spoofax uses this rule to determine the type of a variable declaration. This type is stored as an information about the variable name. ---+++ Types of Use Sites Stored type information can then be used in the typing rules for variable references: type-of: VarRef(x) -> x Types can also determine the context, in which a name should be resolved. For example, in a method call, the type of the first expression determines the callee. This can be expressed in NBL as follows: Call(e, m, _): refers to Method m in Class c where e has type ClassType(c) At this point, you can complete your type system and add missing type constraints.
%GS% _Challenge:_ Try to type =this=. First, pretend that =This()= refers to a field =This()=. Second, define a typing rule which determines the type based on the annotated URI. You can retrieve the path of the URI with =index-uri-path=.
---++ Inheritance Inheritance defines a subtyping relation between super- and subclasses.
%GS% _Challenge:_ Use the index to implement a subtyping relation. First, store inheritance relations as type information. Second, implement a strategy =parent=, which rewrites a class name to the name of its parent class. Next, implement a strategy =ancestor=, which rewrites a class name to a list of its ancestors' names. Make sure that this strategy does not cycle, even in the presence of cyclic inheritance. Finally, implement a strategy =subtype=, which succeeds on a pair of types, if the first type is a subtype of the second type.
Furthermore, it makes fields of the superclass available to the subclass. This can be expressed in NBL in terms of an import: Class(c, Parent(p), _, ms): defines Class c scopes Field refers to Class p imports Field from Class p {transitive} In the current version of NBL, it is important to specify the import on the class level. This might require an adaptation of your existing name binding rules for classes. You can now check inheritance-related constraints. Therefor, you should use import-related strategies from the index API. For example, you can check for overriding fields: constraint-error: Field(_, f) -> (f, $[Overriding field [f]]) where f -- Main.GuidoWachsmuth - 11 Oct 2012