Overview
Trankvila [tranˈkvila] facilitates declarative, value-oriented programming, combining the power of normal-order functional programming languages with concepts of object-oriented languages.
- Simple, conventional syntax inspired by Oberon-2
- Static, hierarchical type system with type extension, type-bound functions, and generics
- Referential transparency and lazy evaluation of function calls without side effects
- Modularity with integrated dependency management for different versions and originators
- Portable Java-based implementation for all major operating systems
Trankvila source code looks like this:
-- lazily evaluated infinite list of Fibonacci numbers fibonacci numbers (first, second: Integer): List [Integer] := first -> fibonacci numbers (second, first + second); all fibonacci numbers := fibonacci numbers (0, 1); -- type-bound functions reversing a list of arbitrary elements (:List) reverse := LIST [T](); (:Nonempty List) ! reverse := nonempty list: rest: reverse + LIST (nonempty list: first); notlob := "bolton": reverse;
Note, that in Trankvila names can consist of more than one word:
fibonacci numbers, nonempty list etc.
News
2018-12-17 |
Okazis prelego pri pure funkciaj programlingvoj en la konferenco
KAEST 2018
kun simplaj programekzemploj en Trankvila.
|
Getting Started
There is no complete description of the programming language yet. However, the formal definition of the
Trankvila Syntax, the interface of the built-in Standard module,
and example code with explanations can already be seen here.
A more comprehensive and practical exploration is possible after downloading
and installing the Trankvila Modules archive:
The source code of
existing Trankvila library and example modules can be inspected, their module
interfaces extracted,
and exported value definitions can be evaluated.
It is also possible to interactively evaluate
Trankvila expressions on the command line
(REPL),
either using only the built-in features of Trankvila, or based on the internal declarations and definitions of a
specific module.
Finally, existing Trankvila modules can be extended and new modules can be created, using either an arbitrary
text editor and the command line compiler,
or the comfortable Eclipse
IDE extended by a special plug-in for Trankvila programming.
See the usage instructions for details.
Examples
Trankvila programs are organized in modules. Modules are identified by a module name, optional version information, and an originator name. The source code of each module is stored in a UTF-8 encoded text file. By convention, each file is stored within a directory named according to the module's originator and named according to the module name with the file extension .trankvila. Modules can contain exported type declarations, functions, and value definitions, which can all be imported and used by other modules. Exported names are marked with an asterisk.
Hello World!
The simple module Hello by fictional originator Acme, without explicit versioning information, is therefore stored as file Acme/Hello.trankvila. It contains the following text:
TRANKVILA MODULE Hello BY Acme; LET hello* := "Hello World!" + new line; END.
The exported name hello refers to a value definition of the string "Hello World!" plus a line break. Its module interface, extracted via the command-line option --interface of the compiler, contains the following information:
TRANKVILA v1.0 MODULE Hello (v1.0) BY Acme; EXPORT hello: Array List [Character]; END.
This shows that the module exports a single value definition hello with the result type Array List [Character]. The result type was automatically determined from the definition with the nonempty string "Hello World!". Since the module does not specify any versioning information, it is assumed to have version v1.0 and require Trankvila version v1.0.
Classic Examples
The module interface of Classic Examples by originator Trankvila is more interesting:
TRANKVILA v1.0 MODULE Classic Examples (v1.0) BY Trankvila; IMPORT Collections := Collections BY Trankvila; EXPORT primes of eratosthenes (up to: Integer): List [Integer]; primes of eratosthenes 10: List [Integer]; primes of eratosthenes 1000: List [Integer]; primes of eratosthenes 10000: List [Integer]; primes of eratosthenes 20000: List [Integer]; primes of eratosthenes with bit sets (up to: Integer): Collections' Bit Set; primes of eratosthenes with bit sets 10 out: List [Character]; primes of eratosthenes with bit sets 1000 out: List [Character]; primes of eratosthenes with bit sets 10000 out: List [Character]; greatest common divisor (a: Integer; b: Integer): Integer; greatest common divisor 1071 462: Integer; factorial 50: Real; factorials 1 to 100: List [Real]; fibonacci number (n: Integer): Integer; fibonacci number 10: Integer; fibonacci number 40: Integer; fibonacci numbers 1 to 50: List [Integer]; quine: List [Character]; END.
This module not only exports several functions and value definitions, but itself imports another module, the library module Collections,
whose exported type declaration Bit Set is also used as the result type of function
primes of eratosthenes with bit sets.
Other modules may on their part import module Classic Examples, call its exported functions and value definitions.
Value definitions like fibonacci number 10, which calculates the 10th
Fibonacci number, can
also be evaluated from the command line and from within the Eclipse IDE.
Another exported function is greatest common divisor, for which the recursive version of the Euclidean algorithm and a value definition greatest common divisor 1071 462 are implemented with the following definitions:
greatest common divisor* (a, b: Integer): Integer := IF b = 0 THEN a ELSE greatest common divisor (b, a % b); greatest common divisor 1071 462* := greatest common divisor (1071, 462);
Recursive functions based on mathematical definitions can, however, also be very inefficient, as the following implementation of Fibonacci number calculation shows. Due to an exponentially increasing number of recursive function invocations, calculating the 40th Fibonacci number can already take several minutes, while the 10th is calculated within milliseconds.
fibonacci number* (n: Integer): Integer := IF n = 0 THEN 0 ELSE IF n = 1 THEN 1 ELSE fibonacci number (n - 1) + fibonacci number (n - 2); fibonacci number 10* := fibonacci number (10); fibonacci number 40* := fibonacci number (40);
An efficient implementation of Fibonacci numbers is, however, easily possible based on a list of previously calculated numbers. Due to lazy evaluation, a function creating an infinite list of numbers can be implemented without providing a termination condition. The Trankvila run-time environment will only create as many list elements as required by the caller. Thus, the value definition fibonacci numbers 1 to 50 can take the first 50 elements from the infinite list of Fibonacci numbers without causing an endless loop.
fibonacci numbers (first, second: Integer): List [Integer] := first -> fibonacci numbers (second, first + second); fibonacci numbers 1 to 50* := fibonacci numbers (0, 1): take (50);
(Operator -> creates a new list by adding a list element to the beginning of another list.)
Lists
Lists are an important built-in data type in Trankvila. They are organized in a type hierarchy, with the root type List, only used for empty lists, and an extended (derived) type Nonempty List for lists with at least one element. Concrete implementations for nonempty lists organized as linked record values (Linked List) or elements within arrays (Array List) are also built-in. The following type declarations show the type hierarchy up to linked lists:
List [T] = RECORD END; Nonempty List = ABSTRACT RECORD (List) END; Linked List = RECORD (Nonempty List) head: T; tail: List [T]; END;
Lists are declared with a type parameter T denoting the required list element type. Therefore, when using a list type,
a type argument has to be provided within brackets. E.g., List [Integer] only accepts list elements with type Integer
or an extension of the integer type.
Root type List does not contain any record fields, since it is only used for empty lists. Type Nonempty List is declared
with keyword ABSTRACT, meaning that no values of this type can be created—it mainly serves as a base type for concrete
implementations of nonempty lists. Type Linked List is one of its extensions, implemented with a record containing the first
list element within record field head and the rest of the list within field tail.
Records can have type-bound functions similar to dynamic methods in object-oriented languages. These are some of the defined type-bound functions of the list type hierarchy:
(:List) is empty := true; (:Nonempty List) ! is empty := false; (:Nonempty List) first : T; (:Nonempty List) rest : List [T]; (:Linked List) first: T := linked list: head; (:Linked List) rest: List [T] := linked list: tail (:List) exists* (:Predicate [T]) := false; (:Nonempty List) ! exists (:Predicate [T]) := predicate (nonempty list: first) OR nonempty list: rest: exists (predicate);
Type-bound function is empty is defined as true for empty lists, and as false for nonempty lists via an overriding
(marked by !) function bound to the abstract type Nonempty List.
The functions first and rest bound to type Nonempty List have no function body, which means that they are
abstract and have
to be implemented by extending types. This is, of course, trivial for the type Linked List.
Type-bound function exists checks if a list contains at least one element fulfilling a specific condition. This condition has to be
specified by a function passed as an argument with the type Predicate.
Predicate* [T] = FUNCTION (value: T): Boolean;
The following example expression passes an anonymous function of this type to type-bound function exists. Called on a string expression, i.e. a list of characters, it checks if the string contains the letter x—the result in this case, of course, being false.
"abc": exists (?(c) c = 'x')
More Examples
The Trankvila Modules archive contains more Trankvila source code within library and example modules.
Syntax
The Trankvila syntax is defined in the following LL (3) grammar.
{...} signifies repeated elements (zero or more), [...] signifies optional elements (zero or one),
alternatives are separated by |. Keywords are written with upper-case letters.
Module = TRANKVILA [Version] MODULE Identifier ["(" Version ")"] Originator ";" [ImportSection] [ExternalReference] [LET [Bindings]] "END.". ImportSection = IMPORT [ImportDefinition {";" ImportDefinition} [";"] ]; ImportDefinition = ImportedModule {"," ImportedModule} Originator; ImportedModule = [Identifier "="] Identifier ["(" Version ")"]. Version = name. Originator = BY Identifier; ExternalReference = EXTERNAL string [";"]. Bindings = BindingBlock {";" BindingBlock} [";"]. BindingBlock = Binding | LocalBindingsBlock. Binding = MarkableIdentifier [TypeParameters] (TypeDeclarationPart | ValueDefinitionPart) | TypeBoundFunction | ":" TypeReference ValueAssignment. LocalBindingsBlock = LOCAL [Bindings] IN [Bindings] END. TypeDeclarationPart = "=" ([ABSTRACT] RecordType | FunctionType). ValueDefinitionPart = [Parameters] [":" TypeReference] ValueAssignment. TypeBoundFunction = "(" [[Identifier] ":"] Identifier ")" ["!"] MarkableIdentifier [TypeParameters] [Parameters] [":" TypeReference] [ValueAssignment]. ValueAssignment = ":=" [EmbeddedBindings] Expression. EmbeddedBindings = "..." [Bindings] "...". Expression = LET [Bindings] IN Expression | IF LogicalExpression [IS TypedBinding] THEN Expression ELSE Expression | ASSERT Expression [IS TypedBinding] ["," Expressions] IN Expression | LOG Expressions IN Expression | ERROR ["(" Expressions ")"] | "?" "(" [Identifier {"," Identifier}] ")" Expression | LogicalExpression. LogicalExpression = LogicalTerm {OR LogicalTerm}. LogicalTerm = LogicalFactor {AND LogicalFactor}. LogicalFactor = [NOT] RelationExpression; RelationExpression = ComparableExpression [("=" | "#" | "<" | "<=" | ">" | ">=") ComparableExpression | IS TypeReference]. ComparableExpression = SimpleExpression ["->" ComparableExpression]. SimpleExpression = ["+" | "-" ] Term {("+" | "-") Term}. Term = Factor {("*" | "/" | "%") Factor}. Factor = SimpleFactor [RecordConstructor] {"(" Expressions ")" | ":" Identifier ["^"] [TypeArguments]}. SimpleFactor = BindingReference | real | integer | string | character | RecordConstructor | ListConstructor | OptionConstructor | SetConstructor | CharacterConstructor | "(" Expression ")". Expressions = Expression {"," Expression}. RecordConstructor = "(" ["^" "(" Expression ")"] [FieldDefinition {"," FieldDefinition}] ")". FieldDefinition = Identifier "!" [Expression]. ListConstructor = LIST [TypeArguments] "(" [Expressions] ")". OptionConstructor = OPTION [TypeArguments] "(" [Expression] ")". SetConstructor = SET "(" [SetElementOrRange {"," SetElementOrRange}] ")". SetElementOrRange = Expression [".." Expression]. CharacterConstructor = CHARACTER "(" Expression ")". TypeReference = BindingReference. RecordType = RECORD ["(" TypeReference ")"] [EmbeddedBindings] [Fields] END. FunctionType = FUNCTION Parameters ":" TypeReference. TypeArguments = "[" TypeReference {"," TypeReference} "]". TypeParameters = "[" TypeParameter {"," TypeParameter} "]". TypeParameter = Identifier ["=" TypeReference]. Parameters = "(" Fields ")". Fields = FieldGroup {";" FieldGroup} [";"]. FieldGroup = [MarkableIdentifier {"," MarkableIdentifier}] ":" TypeReference. BindingReference = (Identifier | importedIdentifier) [TypeArguments]. TypedBinding = [Identifier] ":" TypeReference. Identifier = name. MarkableIdentifier = Identifier ["*"]. importedIdentifier = importedName.
Standard Module
The standard module contains declarations and definitions which are built into the compiler, and thus are available in every module without explicit import declaration and qualified references to the module name. This is its module interface, which can also be shown with the --interface option of the compiler:
TRANKVILA v1.0 MODULE Standard (v1.0) BY Trankvila; EXPORT Boolean = RECORD END; (boolean: Boolean) out: Array List [Character]; true: Boolean; false: Boolean; Integer = RECORD END; (integer: Integer) to real: Real; (integer: Integer) out: Array List [Character]; Real = RECORD END; (real: Real) floor: Integer; (real: Real) out: Array List [Character]; Character = RECORD END; (character: Character) code: Integer; (character: Character) out: Array List [Character]; List [T] = RECORD END; (list: List) length: Integer; (list: List) limited length (limit: Integer): Integer; (list: List) reverse: List [T]; (list: List) collect: List [T]; (list: List) take (length: Integer): List [T]; (list: List) drop (length: Integer): List [T]; (list: List) get (index: Integer): T; (list: List) is empty: Boolean; (list: List) out (element out: Function With Index [T, List [Character]]; separator: List [Character]): List [Character]; (list: List) exists (predicate: Predicate [T]): Boolean; (list: List) map [R] (function with index: Function With Index [T, R]): List [R]; (list: List) take while (predicate with index: Predicate With Index [T]): List [T]; (list: List) drop while (predicate with index: Predicate With Index [T]): List [T]; (list: List) filter (predicate with index: Predicate With Index [T]): List [T]; (list: List) partition (predicate with index: Predicate With Index [T]): Partitioned Lists [T]; (list: List) flat map [R] (function with index: Function With Index [T, List [R]]): List [R]; (list: List) accumulate [R] (initial value: R; function 2: Function 2 [R, T, R]): R; (list: List) reduce [R] (initial value: R; function 2: Function 2 [T, R, R]): R; (list: List) sort (before: Predicate 2 [T, T]): List [T]; (list: List) get option (index: Integer): Option [T]; Nonempty List [T] = ABSTRACT RECORD (List) END; (nonempty list: Nonempty List) first: T; (nonempty list: Nonempty List) rest: List [T]; (nonempty list: Nonempty List) ! length: Integer; (nonempty list: Nonempty List) ! limited length (limit: Integer): Integer; (nonempty list: Nonempty List) ! reverse: Nonempty List [T]; (nonempty list: Nonempty List) ! collect: Nonempty List [T]; (nonempty list: Nonempty List) ! take (length: Integer): List [T]; (nonempty list: Nonempty List) ! drop (length: Integer): List [T]; (nonempty list: Nonempty List) ! get (index: Integer): T; (nonempty list: Nonempty List) ! is empty: Boolean; (nonempty list: Nonempty List) ! exists (predicate: Predicate [T]): Boolean; (nonempty list: Nonempty List) ! accumulate [R] (initial value: R; function 2: Function 2 [R, T, R]): R; (nonempty list: Nonempty List) ! reduce [R] (initial value: R; function 2: Function 2 [T, R, R]): R; (nonempty list: Nonempty List) ! sort (before: Predicate 2 [T, T]): List [T]; Linked List [T] = RECORD (Nonempty List) head: T; tail: List [T]; END; (linked list: Linked List) ! first: T; (linked list: Linked List) ! rest: List [T]; Array List [T] = RECORD (Nonempty List) END; (array list: Array List) ! first: T; (array list: Array List) ! rest: List [T]; (array list: Array List) ! length: Integer; (array list: Array List) ! limited length (limit: Integer): Integer; (array list: Array List) ! reverse: Array List [T]; (array list: Array List) ! collect: Array List [T]; (array list: Array List) ! take (length: Integer): Array List [T]; (array list: Array List) ! drop (length: Integer): Array List [T]; String = List [Character]; Nonempty String = Nonempty List [Character]; Partitioned Lists [T] = RECORD selected: List [T]; rejected: List [T]; END; Option [T] = RECORD END; (option: Option) get: T; (option: Option) get default (default value: T): T; (option: Option) map [R] (function: Function [T, R]): Option [R]; (option: Option) filter (predicate: Predicate [T]): Option [T]; (option: Option) flat map [R] (function: Function [T, Option [R]]): Option [R]; (option: Option) to list: List [T]; (option: Option) out (value out: Function [T, List [Character]]): List [Character]; Provided [T] = RECORD (Option) value: T; END; (provided: Provided) ! get: T; (provided: Provided) ! get default (default value: T): T; (provided: Provided) ! map [R] (function: Function [T, R]): Provided [R]; (provided: Provided) ! filter (predicate: Predicate [T]): Option [T]; (provided: Provided) ! flat map [R] (function: Function [T, Option [R]]): Option [R]; (provided: Provided) ! to list: Array List [T]; (provided: Provided) ! out (value out: Function [T, List [Character]]): List [Character]; Set = RECORD END; (set: Set) contains (value: Integer): Boolean; (set: Set) include (value: Integer): Set; (set: Set) exclude (value: Integer): Set; (set: Set) to list: List [Integer]; (set: Set) include all (values: List [Integer]): Set; (set: Set) exclude all (values: List [Integer]): Set; (set: Set) out: Array List [Character]; (Set) capacity: Integer; (set: Set) filter (predicate with index: Predicate With Index [Integer]): Set; Predicate [T] = FUNCTION (value: T): Boolean; Predicate With Index [T] = FUNCTION (value: T; index: Integer): Boolean; Predicate 2 [T1, T2] = FUNCTION (value 1: T1; value 2: T2): Boolean; Predicate With Index 2 [T1, T2] = FUNCTION (value 1: T1; value 2: T2; index: Integer): Boolean; Function [T, R] = FUNCTION (value: T): R; Function With Index [T, R] = FUNCTION (value: T; index: Integer): R; Function 2 [T1, T2, R] = FUNCTION (value 1: T1; value 2: T2): R; Function With Index 2 [T1, T2, R] = FUNCTION (value 1: T1; value 2: T2; index: Integer): R; concatenate [T] (left list: List [T]; right list: List [T]): List [T]; quote: Array List [Character]; tab: Array List [Character]; new line: Array List [Character]; END.
Downloads
- The Trankvila Modules archive contains the compiler and run-time environment plus a collection of Trankvila library and example modules in the recommended directory structure. Modules can be compiled and executed both from the command line and within the Eclipse IDE (project and configuration files are included).
- The Trankvila Eclipse plug-in can be downloaded within Eclipse via the following update site link: http://trankvila.org/eclipse
- The Trankvila source archive contains the source code of the compiler and run-time environment. Java SE 6 and the Eclipse IDE for Java Developers were used for development.
- The Trankvila Eclipse plug-in source archive contains the source code of the Eclipse plug-in. The Eclipse Plug-in Development Environment was used for development of the plug-in.
Installation
Java SE Run-Time Environment
In order to use the Trankvila implementation, a Java SE run-time environment (minimum version 1.6) is required. Type
java -version
on the command line to check if a suitable version is installed.
Language Implementation and Modules
Download and extract the Trankvila Modules archive. The resulting folder Trankvila Modules has the following content.
Trankvila Modules/ ├── Acme │ └── Hello.trankvila ├── Evaluation of Selected Value Definition.launch ├── Interface of Selected File.launch ├── Interactive Evaluation.launch ├── Interactive Evaluation of Selected File.launch ├── .project ├── .settings │ └── org.eclipse.core.resources.prefs ├── Standard Definitions.launch ├── Trankvila │ ├── Classic Examples.trankvila │ ├── Collections.trankvila │ └── Sudoku Solver.trankvila ├── trankvila.bat ├── trankvila.jar └── trankvila.sh
Files trankvila.jar, trankvila.sh and trankvila.bat contain the language implementation with scripts to facilitate command line usage.
Directories Acme and Trankvila contain the source code of library and example modules. The directory names correspond to the
originators of the modules. Modules are stored as plain text files with UTF-8 encoding and file extension .trankvila.
File .project, folder .settings, and the *.launch files contain configuration data used when importing the folder as a project into the
Eclipse workspace.
The installation is now complete for command line usage.
Eclipse Plug-In
In order to use the Trankvila Eclipse plug-in, an Eclipse Desktop IDE, e.g. the
Eclipse IDE for Java Developers, has to be installed.
Within Eclipse the following steps are necessary to install the Trankvila plug-in:
- Select Install New Software... from the Help menu.
- Use the following location: http://trankvila.org/eclipse
- Select the proposed TrankvilaEclipseFeature (uncategorized)
- Press Next and follow the installation wizard, confirming license agreements etc.
The following Eclipse settings (menu item Window/Preferences resp. Eclipse/Preferences) are recommended for Trankvila development:
- Text file encoding: UTF-8 (General/Workspace)
-
Displayed Tab Width: 8 (General/Editors/Text Editors)
with Insert spaces for tabs left unchecked -
A proportional, sans-serif font as Text Font,
e.g. Verdana or KacstScreen (General/Appearance/Colors and Fonts)
Select Show View from the Window menu to make the following views visible during Trankvila development:
- Project Explorer or Package Explorer
- Problems
Trankvila Modules within Eclipse
The Trankvila Modules folder can be imported into the Eclipse workspace as a project.
- Select File import... from the File menu.
- Choose Existing Projects into Workspace from the General group.
- Press Next and select folder Trankvila Modules as project root directory.
- Press OK and Finish to confirm importing project Trankvila Modules into the workspace.
- Select External Tools/Organize Favorites... from the Run menu or via the tool bar.
- Press Add... and select all available launch configurations.
- Confirm with OK.
On a Windows machine, it is necessary to modify the launch configurations:
- Select External Tools/External Tools Configuration... from the Run menu or via the tool bar.
- For each configuration within group Program:
- Select the configuration name in the tree and go to tab Main.
- Change trankvila.sh to trankvila.bat in the location input field.
- Press Apply to save the changes.
Usage
After successfully downloading and installing the Trankvila modules collection, the language implementation can be used from the command line and, if the Trankvila Eclipse plug-in has also been installed, within the Eclipse IDE.
Command Line Invocation
The root folder of the Trankvila modules collection contains the JAR archive trankvila.jar with the compiler and run-time environment. This is a Java console application which can be started from the command line via the following command:
java -jar trankvila.jar
Without any additional command line arguments, this just prints usage information and example invocations:
usage: java -jar trankvila.jar [options] [source files] options: -m, --module <name> [(<version>)] <originator> compile and load the specified module and its dependencies -f, --file <source file> compile and load the specified file's module with dependencies -x, --interface show module interface of the specified module -e, --evaluate <definition> evaluate exported value definition of the specified module -i, --interactive evaluate expressions interactively (within the scope of a module, if specified) -d, --directory <path> recursively search for *.trankvila source files in this path -v, --verbose show informal messages -?, --help show this information -v, --version show information about the Trankvila version examples: java -jar trankvila.jar --verbose --interactive java -jar trankvila.jar --interface --module Standard Trankvila java -jar trankvila.jar -x -f Trankvila/Classic* -d . java -jar trankvila.jar -m "Sudoku Solver" Trankvila -e "solve 5" -d . java -jar trankvila.jar -v -i -m Hello Acme Acme/*
The command-line tool processes options specifying the tasks to perform, and file arguments specifying the source files to compile.
Compiling
Without any option arguments, the command line tool will just compile the specified files and print error and warning messages. This can be used to check source files for correctness. In addition to explicitly specified single source files, a root directory of Trankvila source files can be provided after option --directory. Then, all files with file name extension .trankvila within this directory and its subdirectories are compiled.
If the module of a specific source file is selected with option --file, or a module, originator, and optionally version are selected after option --module, then only this module and the modules directly or indirectly imported by it are compiled. Other source files are only checked for their module headers.
Error and warning messages are printed according to the following format:
<line number>:<column number>: <message>
The following error message, for example, means that within source file Hello.trankvila in directory Acme,
there is a reference to the unknown identifier something in line 4, column 47.
Acme/Hello.trankvila:4:47: no "something" visible at this position
Column numbers are always calculated according to a tab width of 8 characters.
Within Eclipse, each time a module is interactively evaluated, one of its exported value definitions is evaluated, or its interface is extracted, it is compiled together with all directly and indirectly imported modules.
Also, all modules can be automatically compiled each time a Trankvila source file is saved, if Build Automatically is enabled in the Project menu. This feature can be switched on and off by selecting Enable Trankvila Builder resp. Disable Trankvila Builder in the context menu of the project in the project or package explorer.
Errors and warnings are shown in different ways within the Eclipse IDE:
- View Problems shows a list of errors and warnings according to its configured filters. Clicking on an entry shows the error or warning position in the editor.
- The icons of source files with errors or warnings are displayed with a marker in the project and package explorer.
- Within the text editor view, lines containing errors or warnings are prefixed by a marker, and the text causing the error or warning is underlined. Moving the mouse cursor over the marker reveals a description.
Interactive Mode
Trankvila expressions can be evaluated within a read-eval-print-loop (REPL) on the command line with the following command:
java -jar trankvila.jar --verbose --interactive
Within Eclipse the interactive mode can be started by selecting Interactive Evaluation from the Run/External Tools menu or tool bar item. This shows view Console with the possibility to enter Trankvila expressions.
Expressions may contain local declarations and definitions, and also span multiple lines, when concatenated with character \. The following example dialog in interactive mode shows the evaluation of expressions of different complexity:
Trankvila v1.0 interactive expression evaluation LET inc (:Integer) := integer + 1 IN inc (3) 4 (strict evaluation: 0.001 seconds; total: 0.001 seconds; result type: Integer) SET (1..10): contains (7) true (strict evaluation: 0.0 seconds; total: 0.001 seconds; result type: Boolean) LET first word (:String) := string: take while (?(c) c # ' ') \ IN first word ("Hello World!") Hello (strict evaluation: 0.0 seconds; total: 0.001 seconds; result type: List [Character]) LET \ Point = RECORD x, y: Real END; \ Point 3d = RECORD (Point) z: Real END; \ IN \ Point 3d (x! 1.0, y! 2.0, z! 3.0) (1.0, 2.0, 3.0) (strict evaluation: 0.0 seconds; total: 0.001 seconds; result type: Point 3d) 123 + something 1:7: no "something" visible at this position
The interactive mode can be left by typing Ctrl-D resp. Ctrl-Z (in Windows).
Interactive Evaluation of a Module
If interactive mode is started with options --file or --module, declarations and definitions of the selected module can be used interactively. This way, not only its exported value definitions, but also its internal value definitions can be accessed, and functions can be called with arbitrary argumens. This is useful when testing and debugging the module.
The following commands start interactive evaluation of module Classic Examples; the first one by specifying the source file, the second one by specifying module name and originator. Note, that the directory option -d is also specified in the first command, because module Classic Examples imports another module within the current directory.
java -jar trankvila.jar -i -f "Trankvila/Classic Examples.trankvila" -d . java -jar trankvila.jar -i -m "Classic Examples" Trankvila -d .
Within Eclipse interactive evaluation of a module can be started by selecting (clicking on) the source file of the module in the project or package explorer and selecting Interactive Evaluation of Selected File from the Run/External Tools menu or tool bar item.
Now it is possible, e.g., to test function fibonacci numbers, which is not exported by the module, with different arguments than those of the exported value definition fibonacci numbers 1 to 50:
fibonacci numbers (21, 23): take (7) 21, 23, 44, 67, 111, 178, 289
Extracting the Interface of a Module
Option --interface together with option --file or --module can be used to show the module interface of a module. The following command shows the interface of the Standard module.
java -jar trankvila.jar --interface --module Standard Trankvila
Within Eclipse the same can be achieved by selecting Interface of Module Standard from the Run/External Tools menu or tool bar item. This will show the interface description within view Console.
The interface of other modules can also be extracted based on their file names. The following command shows the interface of module Classic Examples:
java -jar trankvila.jar -x -f "Trankvila/Classic Examples.trankvila" -d .
Within Eclipse the interface of a module can be show in the Console view by selecting (clicking on) its source file in the project or package explorer and then selecting Interface of Selected File from the Run/External Tools menu or tool bar item.
Evaluating Exported Value Definitions
Command line option --evaluate together with option --file or --module is used to evaluate value definitions of a specified module. The following command evaluates the definition fibonacci number 10 from module Classic Examples within source file Trankvila/Classic Examples.trankvila:
java -jar trankvila.jar -f "Trankvila/Classic Examples.trankvila" -e "fibonacci number 10" -d .
Within Eclipse an exported value definition can be evaluated by selecting its name
(without export marker) in the editor view of the module's source file and then
selecting Evaluation of Selected Value Definition
from the Run/External Tools menu or tool bar item.
In the above example this would mean selecting the name fibonacci number 10 in its definition line:
fibonacci number 10* := fibonacci number (10);
License
The Trankvila implementation is free software under the GNU General Public License.
Contact
If you have any questions, comments, or other feedback concerning Trankvila, do not hesitate to send e-mail.