Language
The most important part of Moscrif is JavaScript engine. Moscrif uses extended version of ECMAScript (JavaScript 1.x). Extensions are based on the practical requirements by developers so there are namespaces, classes, constructors, properties, lambda functions, iterators, symbols etc. They are native way implemented, so there is no need to emulate it in script.
Moscrif engine consists of compiler that produces byte code optimised for mobile computing. Another part is virtual machine ported to all supported operating systems. Engine also contains (copying) garbage collector and runtime which implements basic native object classes.
Classes
Moscrif introduces real classes. There is no need to emulate them using JavaScript. Class is declared by keyworld class. Class can contain constructor, functions, properties, variables, constants and other classes.
class MyClass
{
var classVar; // this is “static” !!!
const MY_CONST = 123; // var x = MyClass.MY_CONST;
function this() // function named ‘this’ represents a constructor
{
this._myProp = “my value”;
}
function method()
{
this._myProp = “method has been called”;
}
property myProp(value)
{
get // this is getter
{
assert typeof this._myProp == #string;
return this._myProp;
}
set // this is setter, new value is passed by ‘value’ argument
{
assert typeof value == #string;
this._myProp = value;
}
}
}
Properties
Properties are special kind of class function, used for declaring properties. Properties are accessible normally:
Properties example:
var myClass = new MyClass();
myClass.myProp = “hey, this is property”;
Lambda functions
Moscrif supports named and anonymous (lambda) functions. Anonymous function can be declared in place using following forms:
Single statement function block:
:param1, param2, param3 : statement(param1, param2 + param3);
Lambda function block:
:param1, param2, param3 { var tmp = param2 + param3; statement(param1, tmp); }
Classic anonymous function:
function(param1, param2, param3) { … }
Here is an example of how to sort an array in descending order by using a comparator function that is defined in-place:
Example:
var arr = [1,2,3];
arr.sort(:a, b :a < b ? 1 : -1 );
// arr.sort(:a, b { return a < b ? 1 : -1 });
// arr.sort(function(a, b) { return a < b ? 1 : -1 });
Here, :a,b :a < b ? 1 : -1 is an in-place declaration of a lambda function that will be passed to the Array.sort() method.
Symbols
Symbols are unique names (internally represented by 32-bit integer value). Each symbol is an instance class Symbol and comparison of symbols is effective. Symbol literals are prepended by number sign (#). Moscrif uses symbols for representing special values like undefined (#undefined), true (#true), false (#false) etc. As you can see, symbols may be used as self-descriptive, convenient, and effective auto-enum values. E.g.: stretch of UI control can be expressed as 3 symbols: #start, #center, #end.
Another feature that makes symbols quite useful is the access-by-symbol notation.
Constructions like:
var aa = obj#name;
obj#name = val;
get translated into:
var aa = obj[#name]; // and
obj[#name] = val;
Iterators
By default, in JavaScript we can find for-each statement: for (var item in collection) { … } where the collection is an instance of and object or an array.
In Moscrif, a list of enumerable objects is extended by function instance so the statement for(var item in func) will call the function and execute the body of the loop with its value on each iteration:
function range(from, to)
{
var idx = from - 1;
return function()
{
if (++idx <= to)
return idx;
}
}
will generate consecutive number in range [from..to]. If you write something like this:
for (var item in range(12, 24))
console << item << “\n”;
then you will get numbers from 12 to 24. Here is another example of a class-collection that allows to enumerate its members in two directions:
class Fruits
{
function this()
{
this._data = ["apple","orange","lime","lemon", "pear","banan","kiwi","pineapple"];
}
property forward(v)
{
get {
var items = this._data; var idx = -1;
// return function that will supply "next" value
// on each invocation
return function() { if( ++idx < items.length ) return items[idx]; }
}
}
property backward(v)
{
get {
var items = this._data; var idx = items.length;
return function() { if( --idx >= 0 ) return items[idx]; }
}
}
}
var fruits = new Fruits();
console << "Fruits:\n";
for (var item in fruits.forward)
console << item << "\n";
stdout << "Fruits in opposite direction:\n";
for (var item in fruits.backward)
console << item << "\n";
Decorators
Decorators are a sort of meta-programming feature. Decorator is an ordinary function aimed to modify another function or method. Usually, decorator function creates another function that wraps call of original decorated function with some additional pre- and post-processing. Name of decorator function starts from '@' character, and it must have at least one parameter. That parameter (the first one) is a reference to some other function (or class) that is being decorated. Example of the decorator function - the @returns decorator creates proxy function around call of declaring function and verifies its return value:
// decorator '@returns' - verification of returned value of the function
function @returns(func, return_type)
{
return function(params..)
{
var rv = func.apply(this,params);
if (typeof rv != return_type)
throw String.printf("expected to return %s but got %s", return_type, typeof rv);
return rv;
}
}
Having such decorator in place we can declare methods of classes with checks of their return values:
@returns #integer
function add(a, b) { return a + b; }
Call of the @returns() creates proxy for its parameter function. The result (the proxy function) will be assigned to the add function. As you can see, decorators are pretty much clean syntax that if properly used may considerably increase expressiveness of your code.
A decorator is an advanced feature and may require some effort to understand. When established, decorators can significantly increase the expressiveness of your code.
Native classes & framework
Native object classes are fast and effective base of framework. They expose primary functionalities in native way: core, math, file system, graphics, audio, sqlite databases, network access, GPS, accelerometers, magnetic sensors, physics simulation, 2D operations, views, form controls... all of them and more are native implemented. Moscrif framework use native classes and is distributed as an open source.
Many framework classes contain "native" property that exposes native interface to the programmer. This way, programmer has access to native implementation at all times. The access to native implementation is only suitable when framework class complies with all requirements; however, a few details can be adjusted based on developer’s needs. For example, developers may want to use the Button Class, but if they would like to change its rendering, they can certainly do so.
Visual controls
Visual part of framework is based on native classes such as View, TextView, StackLayout and ScrollView (from now, “view” only). View represents ancestors for every UI component and it can contain “child views” which is used for hierarchy of user’s controls. If “view” contains two or more “child views”, it is possible to apply a layout which places all the child views within the parent view. The view class comes with a default function called StackLayout which places “child views” vertically or horizontally in the application. It allows developers to stretch components referred to as “dock child views” which creates views with list, grid or tiles characteristics. Another part of view class is called ScrollView, which is used to scroll through every “child view” listed. In addition, it is capable of docking the view to a chosen side of the screen.
Applications have to contain some informational value which can be best represented by text. To add text, developers have to use TextView which can display, align and edit particular text and it can be used in single line or multiple line mode. Other framework controls use native controls by adding a set of components and additional, typical controls like Button, ListView, TabBar, ToolBar, etc.
Note: Moscrif components cannot be inherited from a native class. Therefore, every advanced framework feature cannot inherit but must encapsulate View. View is mostly available through "native" property. Having a comfortable development forwards advanced units’ properties and methods.
Libraries
Multiple classes that are logically related are divided into libraries. For instance, all native UI controls fall into Library UI. Native classes like AudioPlayer, AudioRecorder, etc. fall into media category. Library core (system, math, file system) and graphics (Canvas Paint, Shader, Bitmap, etc.) are linked to the standard library. Other libraries have to be explicitly added. (In Moscrif IDE, you can find it as dialogue Project Preferences, folder Global, item Uses). If application uses SQLite database it is necessary to include sqlite in Uses. If it uses accelerometer or GPS, one needs to include the sensor class.
Libraries in Moscrif are included with option:
- lib: includes file from location in current workspace
- app: includes file from location in current project
- data: includes file from current platform working directory. In emulator, working directory is current project location.
//include application.ms from packadge uix located in current workspace
include "lib://uix/application.ms"; //include myClass.ms from current project, root directory
include "app://myClass.ms"; //include settings.dat from platform working directory
include "data://settings.dat";
Publishing
Codebase written in Moscrif can be easily published to all supported platforms because SDK offers complete set of publishing tools. Just one click is enough to create native installation files without installing any additional or related SDK.
Publishing through OpenSource can be initiated without signing or sealing the application. Application of this nature is deployed with source codes and requires a splash screen. These fore-mentioned applications are meant to be used for development, testing, or application of OpenSource model.
Licensing of application development is processed online. Users have to be logged in to their account where they are able to sign the application with required valid license. After this validation, an .app file is sent to Moscrif server which is verified and digitally signed into application file. Only .app file is signed. Signed application is compiled into an installation package.