{"id":15040976,"url":"https://github.com/snapscript/snap","last_synced_at":"2025-04-14T19:36:37.022Z","repository":{"id":57740772,"uuid":"65230059","full_name":"snapscript/snap","owner":"snapscript","description":"Snap Programming Language","archived":false,"fork":false,"pushed_at":"2019-02-09T16:22:02.000Z","size":3875,"stargazers_count":20,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T08:01:45.965Z","etag":null,"topics":["android","android-development","async-await","asynchronous-programming","bnf","coroutines","functional","generic-programming","interpreted-language","interpreter","language","object-oriented","parallel-processing","programming-language","recursive-descent-parser","scripting-language","static-analysis"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snapscript.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-08T18:46:52.000Z","updated_at":"2024-01-13T23:55:39.000Z","dependencies_parsed_at":"2022-08-25T20:41:28.847Z","dependency_job_id":null,"html_url":"https://github.com/snapscript/snap","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapscript%2Fsnap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapscript%2Fsnap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapscript%2Fsnap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapscript%2Fsnap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snapscript","download_url":"https://codeload.github.com/snapscript/snap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248946885,"owners_count":21187588,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-development","async-await","asynchronous-programming","bnf","coroutines","functional","generic-programming","interpreted-language","interpreter","language","object-oriented","parallel-processing","programming-language","recursive-descent-parser","scripting-language","static-analysis"],"created_at":"2024-09-24T20:45:21.507Z","updated_at":"2025-04-14T19:36:36.999Z","avatar_url":"https://github.com/snapscript.png","language":"Java","readme":"![Snap](https://raw.githubusercontent.com/snapscript/snap-site/master/www.snapscript.org/img/logo.png)\n  \nSnap is an optionally typed object oriented language with first class functions and coroutines.\nIt borrows concepts and constructs from many sources including Swift, JavaScript, Java, and \nScala amongst others. It is interpreted and has no intermediate representation, so there is \nno need to compile or build your application.\n\nThe interpreter has been built from the ground up, no tools or libraries have been used. As a result the\nproject is small, fully self contained, and can be either embedded or run as a standalone application. \nHere you will get an overview on how the interpreter works and the language in addition to the debugger \nand development environment.\n  \n  * [Overview](#overview)    \n      * [Parallel Compilation](#parallel-compilation)\n        * [Scanner](#scanner)      \n        * [Grammar](#grammar)      \n        * [Lexical Analysis](#lexical-analysis)\n        * [Parser](#parser)\n        * [Assembler](#assembler)\n      * [Static Analysis](#static-analysis)      \n      * [Evaluation](#evaluation)\n      * [Command Directive](#command-directive)\n      * [Example Programs](#example-programs)\n          * [Mario](#mario)\n          * [Flappy Bird](#flappy-bird)            \n          * [Space Invaders](#space-invaders)\n          * [Tetris](#tetris)      \n  * [Language](#language)      \n      * [Basic Types](#basic-types)\n          * [Booleans](#booleans)\n          * [Numbers](#numbers)\n          * [Strings](#strings)\n          * [Arrays](#arrays)\n          * [Collections](#collections)\n      * [Operators](#operators)\n          * [Arithmetic Operators](#arithmetic-operators)\n          * [Bitwise Operators](#bitwise-operators)          \n          * [Relational Operators](#relational-operators)\n          * [Logical Operators](#logical-operators)      \n      * [Conditions](#conditions)\n          * [If Statement](#if-statement)\n          * [Else Statement](#else-statement)\n          * [Unless Statement](#unless-statement) \n          * [Assert Statement](#assert-statement) \n          * [Debug Statement](#debug-statement)             \n          * [Ternary Operator](#ternary-operator)    \n          * [Null Coalesce](#null-coalesce)                 \n      * [Loops](#loops)\n          * [While Statement](#while-statement)\n          * [Until Statement](#until-statement)      \n          * [For Statement](#for-statement)\n          * [For In Statement](#for-in-statement)\n          * [Loop Statement](#loop-statement)   \n      * [Exceptions](#exceptions)\n          * [Catch Statement](#catch-statement)\n          * [Finally Statement](#finally-statement)   \n      * [Functions](#functions)\n          * [Declaration](#declaration)\n          * [Type Constraints](#type-constraints)      \n          * [Variable Arguments](#variable-arguments)\n          * [Closures](#closures)\n          * [Function Handles](#function-handles)      \n          * [Generic Functions](#generic-functions)\n          * [Coroutines](#coroutines)\n          * [Async Await](#async-await)\n          * [Blank Parameters](#blank-parameters)      \n      * [Types](#types)\n          * [Class](#class)\n          * [Enumeration](#enumeration)      \n          * [Trait](#trait)     \n          * [Module](#module)   \n          * [Annotations](#annotations)           \n          * [Type Alias](#type-alias)\n          * [Uniform Access](#uniform-access)     \n          * [Import](#import)   \n          * [Coercion](#coercion)\n          * [Platform Integration](#platform-integration)  \n  * [Tools](#tools)\n      * [Command Line Interpreter](#command-line-interpreter)\n      * [Development Environment](#development-environment)    \n          * [Breakpoints](#breakpoints)\n          * [Console](#console)\n          * [Variables](#variables)    \n          * [Threads](#threads)    \n          * [Process View](#process-view)    \n          * [Debug Perspective](#debug-perspective)    \n          * [Full Screen](#full-screen)                                                    \n      * [Debug Agent](#debug-agent)\n      * [Android](#android)                                                              \n\n## Overview\n\nSnap is an optionally typed scripting language for the [JVM](https://en.wikipedia.org/wiki/Java_virtual_machine) \nand is compatible with all Android variants\nsuch as [Dalvik](https://en.wikipedia.org/wiki/Dalvik_(software)) and [ART](https://en.wikipedia.org/wiki/Android_Runtime). The learning curve is small for anyone with experience of Java, JavaScript, or a similar \nimperative  language. It has excellent integration with the host platform and can \nleverage the vast ecosystem of the JVM without excessive boilerplate.\n\nThe language is ideal for embedding in to an existing application, and is a fraction of the size \nof similar languages for the JVM platform. In addition to embedding it can be run as a standalone \ninterpreter and has a development environment which allows scripts to be debugged and profiled.\n\n### Parallel Compilation\n\nSnap programs can be separated in to multiple source files that define the types and functions representing \nthe execution flow. To minimise start times the parsing and assembly of the source is performed in parallel. \nOnce defined the execution graph is joined in to a single executable and static analysis is performed.\n\nThe tools and frameworks required to parse and assemble the source code are all custom and written from the \nground up with performance and correctness being the primary goals. In most conventional implementations\na grammar is used to generate the parser, however for flexibility this implementation processes the grammar\nat runtime as the program starts, the parser has no prior knowledge of the grammar. This architecture simplifies \nthe implementation and makes it language agnostic.\n\n#### Scanner\n\nIn the initial phase of compilation the source is passed through a scanner and compressor. This removes \ncomments and command directives from the source text in addition to whitespace that has no semantic value.\nWhen the scanner has completed it emits three segments representing the compressed source text, the line\nnumbers the source was scanned from, and a type index classifying the source characters.\n\n#### Grammar \n\nTo make sense of the source code a custom grammar is required. The grammar used for compilation of\nthe Snap language leverages a custom framework that uses a variant of [Bacus Naur Form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form). It is defined \nusing special rules and literal values that form the basis of a [Recursive Descendant Parser](https://en.wikipedia.org/wiki/Recursive_descent_parser).\n\n| Rule  | Semantics |\n| ------------- | ------------- |\n| \u0026#124;       | Represents a logical OR  |\n| \u0026#42;       | Represents one or more  |\n| \u0026#43;       | Represents at least once |\n| ?      | Represents one or none  |\n| \u0026lt;\u0026gt;       | Define a production |\n| ()       | Group productions and literals  |\n| {}       | Group productions where first match wins  |\n| _       | Represents whitespace |\n| []      | Represents a symbol  |\n| ''       | Represents a literal text value  |\n\nThe formal grammar for the language is defined with these rules, it can be modified to extend the language\nor tweak existing behaviour. \n\n[Language Grammar](https://github.com/snapscript/snap/blob/master/snap-parse/src/main/resources/grammar.txt)\n\n#### Lexical Analysis\n\nThe lexical analysis phase indexes the source in to a stream of tokens or lexemes. A token can represent\none or more primitive character sequences that are known to the parser. For example a quoted string, a \ndecimal number, or perhaps a known keyword defined in the grammar. To categorise the tokens the formal\ngrammar is indexed in to a sequence of literals. If a token matches a known literal then it\nis classified as a literal. Any given token can contain a number of separate classifications which enables\nthe parser to determine based on the grammar and its context what the token represents.\n\nWhen this phase of processing completes there is an ordered sequence of classified tokens. Each token\nwill have the line number it was extracted from in addition to a bitmask describing the classifications\nit has received. It is up to the parser to map these tokens to the formal grammar.\n\n#### Parser\n\nThe parser consumes the sequence of categorised tokens produced by the lexer. The parser has backtracking\nsemantics and is performed in two phases. The first phase is to the map the tokens against the grammar and\nthe second phase is to produce an [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree).\n\n#### Assembler\n\nThe final phase of the compilation process is assembly. This process uses a configured set of instructions\nto map top level grammars to nodes within an execution graph. Configuring a set of instructions facilitates\na dependency injection mechanism which is used to build the program. \n\nThe syntax tree is traversed in a depth first manner to determine what the instruction dependencies are needed. As the\ntraversal retreats back up from the leafs of the tree to the root instructions are assembled. This process is\nsimilar to how many other dependency injection system works.\n\n[Language Instructions](https://github.com/snapscript/snap/blob/master/snap-tree/src/main/resources/instruction.txt)\n\n### Static Analysis\n\nAs a program grows large so to does its complexity. To manage this complexity static analysis is performed across \nthe entire codebase. The level of static analysis performed is up to the developer as types are optional. Access \nmodifiers are also provided to describe intent and visibility of functions and variables.\n\nWhen leveraging types further qualification can be given in the form of generics. [Generics](https://en.wikipedia.org/wiki/Generic_programming) allow the developer\nto describe the types of parameters that can be used for a specific declaration. \n\n### Evaluation\n\nCode evaluation is the process of transforming text to code at runtime. This can be useful when you want\nto perform some dynamic task. In languages such as Java the reflection framework allows developers to \nintrospect and execute code in a dynamic way. With evaluation you can achieve similar functionality without\nthe boilerplate. Internally evaluations cache the execution trees they represent which eliminates \nthe performance overheads.\n\n```js\nlet instance = eval(\"new \" + type + \"()\");\n```\n\n\n### Command Directive\n\nThe command directive is used to tell command interpreters where the interpreter for the source is located. This is \nis often called the [Shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) directive and is interpreted by common shells like bash. The first line of any Snap \nsource file can contain this command directive.\n\n```sh\n#!/usr/bin/env snap\n```\n\n### Example Programs\n\nThe best way to learn any language is through examples. Below is a collection of examples from applications that\nhave been written in Snap. The source code for these examples are available on Github and are free to download.\n\n#### Mario\n\nThis is a clone of the [Mario](https://en.wikipedia.org/wiki/Mario_Bros.) game comes with the full source code in addition to the images and sounds. It has\nbeen written twice, once with full static typing and one with dynamic typing. Below is a YouTube video of the \nprogram being run and debugged with Snap Studio.\n\n[![Debug Desktop Game](http://img.youtube.com/vi/6vo2y83unG0/0.jpg)](https://www.youtube.com/watch?v=6vo2y83unG0)\n\n##### Statically Typed\n\nThe statically typed implementation performs type checking throughout.\n\n[Source Code](https://github.com/snapscript/snap-develop/tree/master/snap-studio/work/demo/games/src/mario)\n\n##### Dynamically Typed\n\nThe dynamically typed implementation is identical to the statically typed implementation without type\nconstraints.\n\n[Source Code](https://github.com/snapscript/snap-develop/tree/master/snap-studio/work/games/mario/src/mario)\n   \n##### Android   \n\nIn order to run on Android a framework was required to perform double buffering and map user\nactions to program behaviour. The Android game framework can be found on Github within this profile.\n   \n[Source Code](https://github.com/snapscript/snap-develop/blob/master/snap-studio/work/android/mario/src/mario/start.snap)\n\n#### Flappy Bird\n\nThis is a clone of the [Flappy Bird](https://en.wikipedia.org/wiki/Flappy_Bird) game and is targeted for Android. Below is a YouTube vide of the application\nbeing run and debugged remotely with Snap Studio.\n\n[![Debug Android Game](http://img.youtube.com/vi/w-baBQbZ5dI/0.jpg)](https://www.youtube.com/watch?v=w-baBQbZ5dI)\n\n[Source Code](https://github.com/snapscript/snap-develop/tree/master/snap-studio/work/android/flappybird/src/flappybird)\n        \n#### Space Invaders\n\nThis is a very basic clone of the classic [Space Invaders](https://en.wikipedia.org/wiki/Space_Invaders) game. The implementation is short but leverages some\nof the more interesting language features such as async await.\n\n[Source Code](https://github.com/snapscript/snap-develop/tree/master/snap-studio/work/demo/games/src/spaceinvaders)\n  \n#### Tetris\n\nThis is a very basic clone of the classic [Tetris](https://en.wikipedia.org/wiki/Tetris) game. The implementation does not leverage graphics or sounds and\nshapes are painted on the screen with AWT primitives.\n\n[Source Code](https://github.com/snapscript/snap-develop/tree/master/snap-studio/work/demo/games/src/tetris)\n  \n### Language  \n  \nLearning how to code applications with Snap is easy, particularly if you have experience with Java, Javascript, \nor a similar language. Below you will find various sections illustrating the basics, where you will learn about \ntypes, functions, and the various statements and expressions that can be used. \n  \n#### Basic Types\n\nFor programs to be useful, we need to be able to work with some of the simplest units of data such as numbers, \nstrings, structures, boolean values, and the like. Support for these basic types is much the same as you would \nexpected for Java, with some additional features such as string templates, map, set, and list literals.\n\nIn order to reference values they must be associated with a variable. Variables are declared with the keyword \n```let``` or ```const```. A variable can have an optional constraint by declaring a type. If constrained a \nvariable can only reference values of the declared type.\n\n```js\nlet v = 22; // v can reference any type\nlet i: Integer = 22; // i can only reference integers\nlet d: Double = 22.0; // d can only reference doubles\nconst c = 1.23; // c is constant, it cannot change\n```\n\n##### Booleans\n\nThe most basic type is the simple true or false value, which is called a boolean value.\n\n```js\nlet a = true; // value a is true\nlet b = false; // false\nlet c = Boolean.FALSE; // type constraint of Boolean\nlet d: Boolean = Boolean.TRUE; // like Boolean d = Boolean.TRUE\nlet e = Boolean.FALSE; // like Object e = Boolean.FALSE\n```\n\n##### Numbers\n\nThe most basic type is the simple true or false value, which is called a 'boolean' value.\n\n```js\nlet binary = 0b0111011; // binary literal\nlet hex = 0xffe16; // hexidecimal literal\nlet int = 11;\nlet real = 2.13;\nlet typed: Integer = 22; // integer value 22\nlet coercion: Double = \"1.234e2\"; // coercion of string to double\n```\n\n##### Strings\n\nA fundamental part of creating programs is working with textual data. As in other languages, \nwe use the type string to refer to these textual types. Strings are represented by characters \nbetween a single quote, a double quote, or a backtick. When characters are between double quotes \nor backticks they are interpolated, meaning they have expressions evaluated within them. These \nexpressions start with the dollar character. All strings can span multiple lines.\n\n```rust\nlet string = 'Hello World!'; // literal string\nlet template = \"The sum of 1 and 2 is ${1 + 2}\"; // interpolated string\nlet concat = \"The sum of 1 and 2 is \" + (1 + 2); // concatenation\n\nlet multiline = \"Details\n    a) This is a new line\n    b) This is another new line\";\n    \nlet backtick = `A backtick can contain \"quotes\" and ${expressions}\n    and can span multiple lines`;    \n```\n\n##### Arrays\n\nTo allocate an contiguous sequence of memory an array is required. An array can be created from\nany type, however arrays of numbers or bytes are created as primitive arrays internally. These\nprimitive arrays provide better integration with streams and buffers. \n\n```js\nlet array = new String[10]; // array of strings\nlet bytes = new Byte[11]; // primitive byte[11]\nlet byte = array[1]; // reference element in array\nlet matrix = new Long[10][22]; // multidimensional long[10][22];\nlet long = matrix[2][3]; // reference multidimensional\n```\n\n#### Collections\n\nComplex data structures can be represented with a simple and straight forward syntax. Collection \ntypes found in Java such as maps, sets, and lists can be represented as follows.\n\n```js\nlet set = {1, 2, \"x\", \"y\"}; // creates a LinkedHashSet\nlet list = [1, 2, 3]; // creates an ArrayList\nlet map = {\"a\": 1, \"b\": 2}; // creates a LinkedHashSet\nlet empty = {:}; // creates an empty map\nlet mix = [1, 2, {\"a\": {\"a\", \"b\", [55, 66]}}]; // mix collection types\n\nlet multiline = {\n    name: \"John Doe\",\n    address: {\n        city: \"Unknown\",\n        state: \"California\"\n    },\n    age: 33\n};\n\nlet ascending = [0 to 9]; // range of increasing numbers\nlet descending = [0 from 9]; // range of decreasing numbers\n```\n\n### Operators\n\nOperators are special symbols that perform specific operations on a set of operands. The operators\navailable are those found in most conventional imperative languages, such as those to perform\nalgebra or compare values. \n\n\n#### Arithmetic Operators\n\nArithmetic operators are used in mathematical expressions in the same way that they are used in algebra.\nThese operations can be grouped and order can be specified using braces.\n\n```js\nlet a = 10;\nlet b = 20;\nlet c = a + b; // add is 30\nlet d = b - a; // subtract is 10\nlet e = b / a; // divide is 2\nlet f = a * b; // multiply is 200\nlet g = b % a; // modulus is 0\nlet h = a++; // a is 11 and h is 10\nlet i = b--// b is 19 and i is 20\nlet j = --a; // a is 10 and j is 10\nlet k = ++b; // b is 20 as is k\nlet l = 1 / ((a + b) * 10)\n```\n\n#### Bitwise Operators\n\nBitwise operators are used to manipulate numbers, typically integers, at the byte level. They do so by change the binary representation of the value.\n\n```js\nlet a = 0b00111100;\nlet b = 0b00001101;\nlet c = a \u0026 b; // bitwise and, c is 00001100\nlet d = a | b; // bitwise or, d is 00111101\nlet e = a \u0026 b; // bitwise xor, e is 00110001\nlet f = ~a; // f is 11000011\nlet g = f \u003e\u003e 2; // f is 00110000\nlet h = f \u003c\u003c 2; // h is 11000000\nlet i = f \u003e\u003e\u003e 2; // unsigned shift, i is 00110000\n```\n\nBoth the arithmetic and bitwise operators have priority and are evaluated in a specific order if no\nbraces are used to group or enforce order. The evaluation order applied is shown in the table below.\n   \n|Order| Operator      | Description |\n|-----| ------------- | ------------- |\n|1    |\u0026#42;\u0026#42;     |Exponential operator|\n|2    |/              |Divide operator|\n|3    |\u0026#42;          |Multiply operator|\n|4    |%              |Modulus operator|\n|5    |+              |Addition operator|\n|6    |-              |Subtraction operator|\n|7    |\u0026gt;\u0026gt;       |Signed shift right operator|\n|8    |\u0026lt;\u0026lt;       |Shift left operator|\n|9    |\u0026gt;\u0026gt;\u0026gt;   |Shift right operator|\n|10   |\u0026              |Bitwise AND operator|\n|11   |\u0026#124;         |Bitwise OR operator|\n|12   |^              |Bitwise XOR operator|\n\n\n#### Relational Operators\n\nRelational operators are used to make comparisons, such as equal to, not equal to, greater than, less than.\n\n```js\nlet a = 10;\nlet b = 20;\nlet c = a == b // equal operator, c is false\nlet d = a != b; // not equal operator, d is true\nlet e = a \u003e b; // greater than operator, e is false\nlet f = a \u003c b; // less than operator, f is true\nlet g = a \u003c= b; // g is false\nlet h = a \u003e= b; // h is true\n```\n\n#### Logical Operators\n\nLogical operators are typically used to combine multiple relational operations in to a single boolean result.\n\n```js\nlet a = 1;\nlet b = 3;\nlet c = true;\nlet d = false;\nlet e = a \u0026\u0026 b; // e is false\nlet f = a || b; // f is true\nlet g = !d; // not operator, g is true\nlet h = b \u003e a \u0026\u0026 a == 1; // logical and of, h is true\nlet i = b \u003e a \u0026\u0026 a != 1; // i is false\n```\n\n### Conditions\n\nConditional statements are used to perform different actions based on different conditions.\n\n\n#### If Statement\n\nThe if statement is used to specify a group of statements to execute if a statement is true.\n\n```js\nconst a = 2;\nconst b = 3;\n\nif(a \u003c b) { // true\n   println(\"a \u003e b\"); // prints as a \u003c b\n}\n```\n\n#### Else Statement\n\nThe else statement is used to specify a group of statements to execute if a statement is false.\n\n```js\nconst a = 2;\nconst b = 3;\n\nif(a \u003e= b) { // false\n   println(\"a \u003e= b\");\n} else {\n   println(\"a \u003c b\"); // prints as a \u003c b\n}\n```\n\n#### Unless Statement\n\nThe unless statement is used to specify a group of statements to execute if a statement is false.\n\n```js\nconst a = 2;\nconst b = 3;\n\nunless(a \u003e b) { // false\n   println(\"a \u003e b\"); // prints as a \u003c b\n}\n```\n\n#### Assert Statement\n\nThe assert statement is used to determine if an expression evaluates to true or false. If the expression evaluates \nto true the operation has no effect, otherwise an assertion exception is thrown.\n\n```js\nconst a = 2;\nconst b = 3;\n\nassert a \u003c b;\nassert a \u003e b; // assert exception\n```\n\n#### Debug Statement\n\nThe debug statement is used to suspend any attached debugger if and expression evaluates to true. This can be useful\nif there is a specific part of the program that you want to evaluate given a known state of execution. It is similar\nto the debugger statement for JavaScript with the addition of logic predicate the suspension.\n\n```js   \ndebug a * b \u003e 4; // suspend the debugger if true\n```\n\n#### Ternary Operator\n\nTo make statements more concise there is a ternary operator.\n\n```js\nlet a = 2;\nlet b = 3;\n\nprintln(a \u003e= b ? \"a \u003e= b\" : \"a \u003c b\"); // prints a \u003c b\n```\n\n#### Null Coalesce\n\nThe null coalesce operator is similar to the ternary operator with one exception, the evaluation is whether a value is null.\n\n```js\nlet a = null;\nlet b = 3;\n\nprintln(a ?? b); // prints b\n```\n\n### Loops\n\nLoops are used to perform a group of statements a number of times until a condition has been satisfied.\n\n#### While Statement\n\nThe while statement is the simplest conditional statement. It repeats a group of statements while the \ncondition it evaluates is false.\n\n```js\nlet n = 0;\n\nwhile(n \u003c 10) { // conditional loop\n   n++;\n}\n```\n#### Until Statement\n\nThe until statement is similar to the while statement but loops while the condition is false. It repeats \na group of statements until the condition it evaluates is true.\n\n```js\nlet n = 0;\n\nuntil(n \u003e= 10) { // conditional loop\n   n++;\n}\n```\n#### For Statement\n\nThe for statement is typically used to count over a range of numeric values. It contains three parts, a \ndeclaration, a condition, and an optional statement which is evaluated at the end of the loop.\n\n```js\nfor(let i = 0; i \u003c 10; i++){ // loops from 1 to 10\n   if(i % 2 == 0) {\n      continue; // continue loop\n   }\n   println(i);  // prints only odd numbers\n}\n```\n\n#### For In Statement\n\nThe for in statement offers a simpler way to iterate over a range of values, a collection, or an array.\n\n```js\nlet list = [35, 22, 13, 64, 53];\n\nfor(e in list){ // iterates over the list\n   println(e);\n}\n\nfor(e in 0..9) { // iterates from 0 to 9\n   if(e == 7) {\n      break; // exit loop when e is 7\n   }\n   println(e); // prints from 0 to 6\n}\n\nfor(i in 0 to 9) { // iterates from 0 to 9\n    println(i);\n}\n\nfor(i in 0 from 9) { // iterates from 9 to 0\n    println(i)\n}\n```\n#### Loop Statement\n\nThe loop statement offers a way to specify an infinite loop, it does not evaluate any condition.\n\n```js\nlet n = 0;\n\nloop { // infinite loop\n   if(n++ \u003e 100) {\n      break;\n   }\n}\n```\n\n### Exceptions\n\nExceptions are used to indicate an error has occurred. It offers a simple means to return control to a \ncalling function, which can then handle the error. Typically an exception object is thrown, however it is \npossible to throw any type.\n\n#### Catch Statement\n\nIn order to catch an exception the throwing statement needs to be wrapped in a try catch statement. This \nstatement basically allows the program to try to execute a statement or group of statements, if during \nexecution an exception is thrown then an error handling block is executed.\n\n```js\ntry {\n   throw new IllegalStateException(\"some error\");\n} catch(e: IllegalStateException) {\n   e.printStackTrace();\n}\n```\n\n#### Finally Statement\n\nThe finally statement is a group of statements that are always executed regardless of whether an exception is thrown.\n\n```js\ntry {\n   throw \"throw a string value\";\n} catch(e) {\n   println(e);\n} finally {\n   println(\"finally always runs\");\n}\n```\n\n### Functions\n\nFunctions group together control structures, operations, and method calls. These functions can then be called when needed, and the code contained within them will be run. This makes it very easy to reuse code without having to repeat it within your script.\n\n#### Declaration\n\nThe most basic type of function is declared with a name and a specific number of parameters. Such a method can then be called using the declared name by passing in a right number of arguments.\n\n```js\nlet r = max(11, 3, 67); // r is 67\n\nfunc max(a, b) {\n   return a \u003e b ? a : b;\n}\n\nfunc max(a, b, c) { // function overloading\n   return a \u003c b ? max(a, c) : max(b, c);\n}\n```\n\n#### Type Constraints\n\nIn order to bind invocations to the correct function implementation it can be declared with optional type constraints. These type constraints will ensure that variables of a specific type will be bound to the correct implementation.\n\n```js\nlet x: Double = 11.2;\nlet y: Integer = 11;\nlet z: String = \"11\";\n\nf(x); // prints double 11.2\nf(y); // prints integer 11\nf(z); // prints string 11\nf(true); // type coercion to string, prints string true\n\nfunc f(x: Integer) {\n   println(\"integer ${x}\");\n}\n\nfunc f(x: Double) {\n   println(\"double ${x}\");\n}\n\nfunc f(x: String) {\n   println(\"string ${x}\");\n}\n```\n\n#### Variable Arguments\n\nAt times it can be useful to provide a large number of arguments to a function. To achieve this the last parameter can be declared with a variable argument modifier.\n\n```js\nlet result = sum(0, 13, 44, 234, 1, 3); \n\nfunc sum(offset, numbers...){ // variable arguments\n   let size = numbers.size();\n   let sum = 0;\n   \n   for(let i = offset; i \u003c size; i++){\n      sum += number;\n   }\n   return sum;\n}\n```\n\n#### Closures\n\nA closure is an anonymous function that captures the current scope and can be assigned to a variable. This variable can then act as a function and can be called in the same manner.\n\n```js\nconst square = (x) -\u003e x * x;\nconst cube = (x) -\u003e square(x) * x;\n\ncube(2); // result is 8\n\nconst printAll = (values...) -\u003e {\n   for(var e in values) {\n      println(e);\n   }\n}\n\nprintAll(1, 2, 3, 4); // print all values\n```\n\n#### Function Handles\n\nA function handle is simply a way to reference an existing function as a closure. Function handles can represent constructors or functions that are in scope.\nFor example take the constructor for a string, it is quite possible to execute the following.\n\n```js\n['a', 'b', 'c'].iterator.forEachRemaining(this::println)\n```\n\nHere we are calling the println function with the item passed to the function. This function is represented as a function handle\nthat takes a string. A function handle can represent a static or an instance function. For example:\n\n```js\nclass Formatter {\n\n    public static upper(s: String) {\n        return s.toUpperCase();\n    }\n}\n\n['a', 'b', 'c'].stream().map(Formatter::upper).forEach(this::println);\n```\n\n#### Generic Functions\n\nGenerics can be used to qualify the arguments that can be passed to a function. They are useful when the static analyser verifies the program as it ensures arguments and return types match the declared qualifiers.\n\n```js\nfunc abs\u003cT: Number\u003e(nums: T): List\u003cT\u003e {\n    let result: List\u003cT\u003e  = [];\n    \n    for(num in nums) {\n        let abs = num.abs();\n        result.add(abs);\n    }\n    return result;\n}\n\nlet list: List\u003cDouble\u003e = abs\u003cDouble\u003e(-1.0, 2.0, -3.0);\n\nassert list[0] == 1;\nassert list[2] == 2;\n```\n\n#### Coroutines\n\nIt is often useful to suspend execution of a function in order to return a result. Typically this requires a great deal of effort from the developer. [Coroutines](https://en.wikipedia.org/wiki/Coroutine) \nallow an idiomatic means of suspending the execution of a function which can be resumed at the point of \nsuspension. This allows for complex reactive iteration to be performed with minimal effort. For example \ntake a Fibonnaci sequence.\n\n```js\nfunc fib(n){\n   let a = 1;\n   let b = 2;\n   \n   until(n-- \u003c= 0) {\n      yield a; // function is suspended here\n      (a, b) = (b, a + b);\n   }\n}\n```\n\n#### Async Await\n\nAsynchronous functions can be implemented with the async and await modifiers. This is similar to a standard Coroutine however this paradigm will allow the execution\nof the program to fork in two different threads of execution.\n\n```js\nasync loadImage(n: String): Promise\u003c?\u003e {\n    if(!cache.contains(n)) {\n        return await ImageIO.read(n); \n    }\n    return cache.get(n); // no need to go async\n}\n```\n\nAll async functions can cascade such that if an async function calls another it is suspended until the function\nbeing called completes, at which point it will resume from the call site. For convenience closures can also\nbe asynchronous.\n\n```js\nlet loadImage = async (n: String) -\u003e ImageIO.read(n);\n```\n\nHere there is no need to specify the await keyword as expression based asynchronous closures have an implicit await.\nFor closures that have more than a single expression you must specify which statements are asynchronous.\n\n```js\nlet loadImage = async (n: String) -\u003e {\n    if(!cache.contains(n)) {\n        return await ImageIO.read(n); \n    }\n    return cache.get(n); // no need to go async\n}\n```\n\n#### Blank Parameters\n\nBlank parameters allow you to specify an argument that is not needed or can be ignored.\n\n```js\nfunc create\u003cT\u003e(type: T): T {\n    return cache.computeIfAbsent(type.name, (_) -\u003e new T());\n}\n```\n\n### Types\n\nIn any object oriented language types are required. A type is basically a way to define and encapsulate variables \nand functions within a named scope. All types can have generic parameters allowing the static analyser to verify\ninteractions with the type.\n\nThe type system for Snap is independent to the type system native to the JVM. To integrate with the JVM type\nsystem ASM byte code generation and Dex code generation are leveraged to create bridges between native\ntypes and those constructed from the script execution flow.\n\n#### Class\n\nA class is the most basic type. It contains variables, and functions that can operate on those variables. \nOnce declared a type can be instantiated by calling a special function called a constructor. There are two\nprimary categories of class, the abstract class and the concrete class. An abstract class represents\na generic concept and as such cannot be instantiated. Below is an example of an abstract class.\n\n```js\nabstract class Shape {\n\n    let origin: Point;\n    \n    new(origin: Point) {\n       this.origin = origin;\n    }\n\n    /**\n     * Draw the shape to the provided graphics. Each\n     * shape will be drawn from the origin.\n     *\n     * @param g the graphics to draw with\n     */\n    abstract draw(g: Graphics);\n    \n    class Point { // inner class\n    \n        const x;\n        const y;\n        \n        new(x, y) {\n            this.x = x;\n            this.y = y;\n        }\n    }\n}\n```\n\nA concrete class represents an whole object or entity and unlike abstract classes it can be instantiated.\nTo leverage methods and state from other classes inheritance is possible. Below we can see how a square\ninherits state and a method from the abstract shape class. \n\n```js\nclass Square extends Shape {\n\n    private let width: Integer;\n    private let height: Integer;\n\n    new(origin: Point, width: Integer, height: Integer): super(origin) {\n        this.width = width;\n        this.height = height;\n    }\n    \n    /**\n     * Draw a square at the origin.\n     *\n     * @param g the graphics to draw on\n     */\n    override draw(g: Graphics) {\n        g.drawSquare(origin.x, origin.y, width, height);\n    }\n}\n```\n\nBy default functions defined in the body of a class are public. This means any scope where an instance\nof the class is accessible can call this public method. The opposite is true for private methods. Private\nmethod can be called only within the body of the class. \n\nBelow is a list of the modifiers that can be applied to functions defined within the body of a class.\n\n| Modifiers     | Description |\n| ------------- | ------------- |\n|public    |Public functions and variables are visible in all scopes|\n|private    |Private functions are visible only within the class body|\n|abstract    |Abstract functions have no implementation|\n|override    |An override reflects replacing a super class function|\n|static    |Static methods can be called without an instance|\n|async    |Async functions can be suspended and resumed concurrently|\n\n\n#### Enumeration\n\nAn enumeration is a type that specifies a list of constant values. This values are constant and are instances of the enum they are declared in.\n\n```js\nenum Color {\n   RED(\"#ff0000\"),\n   BLUE(\"#0000ff\"),\n   GREEN(\"#00ff00\");\n   \n   let rgb;\n   \n   new(rgb) {\n      this.rgb = rgb;\n   }\n}\n\nlet red = Color.RED;\nlet blue = Color.BLUE;\n```\n\n#### Trait\n\nA trait is similar to a class in that is specifies a list of functions. However, unlike a class a trait \ndoes not declare any variables and does not have a constructor. It can be used to add functions to a class.\n\n```js\ntrait NumberFormat\u003cT: Number\u003e {\n   \n   /**\n    * Round to number to a specific number of decimal\n    * places or to an integer.\n    *\n    * @param a places to round to\n    */\n   round(a): T;\n   \n   format(a: T) {\n      return round(a);\n   }\n}\n\nclass DoubleFormat with NumberFormat\u003cDouble\u003e {\n   \n   let places: Integer;\n   \n   new(places: Integer) {\n      this.places = places;\n   }\n   \n   override round(a: Double) {\n      return a.round(places);\n   }\n}\n\nclass IntegerFormat with NumberFormat\u003cInteger\u003e {\n   \n   override round(a: Integer) {\n      return a;\n   }\n}\n```\n\n#### Module\n\nA module is collection of types, functions, and variables. It is similar to enclosing a script within a named type. \nModules are useful in providing constructs such as singletons.\n\n```js\nmodule ImageStore {\n\n   private const cache = {:};\n   \n   public find(name) {\n      return cache.get(name);\n   }\n   \n   private cache(name, image) {\n      cache.put(name, image);\n   }\n} \n```\n\n#### Annotations\n\nAnnotations can be applied to any type and do not need to be declared. These are useful when\nyou need to determine the behaviour of a type and its methods through introspection.\n\n```java\n@ComponentPath(path: '/images')\nclass ImageService {\n\n    @Path(match = \"/{path}')\n    @Method(verb: 'GET')\n    @ContentType(value: 'image/png')\n    getImage(@Param(name: 'path') path) {\n        return ImageIO.read(path);\n    }\n}\n```\n\n#### Type Alias\n\nIt can often be useful to alias types for readability, particularly when generics are involved. An alias is not\na new type but rather a new name for a known type. \n\n```js\nimport util.concurrent.ConcurrentHashMap;\n\ntype Bag\u003cT\u003e = ConcurrentHashMap\u003cString, T\u003e();\n\nfunc bagOf\u003cT: Number\u003e(nums...: T): Bag\u003cT\u003e {\n    let bag: Bag\u003cT\u003e = new Bag\u003cT\u003e();\n    \n    for(num in nums){\n        bag.put(`${num}`, num);\n    }\n    return bag;\n}\n```\n\n#### Uniform Access\n\nThe uniform access principle of computer programming was put forth by Bertrand Meyer\nin his book called [Object Oriented Software Construction](https://en.wikipedia.org/wiki/Object-Oriented_Software_Construction). \nIt states all services offered by a module should be available through a uniform notation, \nwhich does not betray whether they are implemented through storage or through computation.\nAn example of this is typical getter and setter property methods but applies to any\nmethod that does not require arguments.\n\n```js\nclass Person {\n    \n    private const firstName;\n    private const surname;\n    \n    new(firstName, surname) {\n        this.firstName = firstName;\n        this.surname = surname;\n    }\n    \n    getFullName() {\n        return \"${firstName} ${surname}\";\n    }\n}\n\nlet person = new Person(\"John\", \"Doe\");\n\nassert person.fullName == 'John Doe';\n```\nUniform access applies to all implemented types as well as any external dependencies imported \nregardless of their origin, for example the Java class libraries.\n\n#### Import\n\nIn order to access the Java types available they can be imported by name. Once imported the type can be instantiated \nand used as if it was a script object. In addition to importing types, functions can also be imported by using a \nstatic import.\n\n```js\nimport static lang.Math.*; // import static functions\nimport security.SecureRandom;\n\nconst random = new SecureRandom(); // create a java type\nconst a = random.nextInt(40);\nconst b = random.nextInt(40);\nconst c = max(a, b); // Math.max(a, b)\n\nprintln(c); // prints the maximum random\n```\n\nTo avoid name collisions it is also possible to import types with aliases. Additionally an imports visibility can\nbe encapsulated within a module so that it is only available in that module. \n\n```js\nimport util.concurrent.ConcurrentHashMap as Bag;\n\nmodule ImageStore {\n\n    import aws.image.BufferedImage as Image;\n    import aws.Graphics;\n    \n    public paint(g: Graphics) {\n        // ...\n    }\n}\n```\n\nImports can be grouped from the same package using braces. Below is an example of \nimport groups.\n\n```js\nimport util.concurrent.{ ConcurrentHashMap, CopyOnWriteArrayList };\nimport util.{ Map, Set, List };\n```\n\n\n#### Coercion\n\nFor interfaces that have only a single method a closure can be coerced to that interface type. This makes for a much simpler and concise syntax similar to that offered by Java closures.\n\n```js\nconst set = new TreeSet(Double::compare);\n\nset.add(1.2);\nset.add(2.3);\nset.add(33.4);\nset.add(4.55);\nset.add(2);\n\nfor(entry in set){\n   println(entry);\n}\n```\n\n#### Platform Integration\n\nTo leverage the large array of frameworks and services available on the Java platform any Java type \ncan be instantiated, and any Java interface can be implemented.\n\n```js\nclass DoubleComparator with Comparator{\n\n   override compare(a,b){\n      return Double.compare(a,b);\n   }\n}\n\nlet comparator = new DoubleComparator();\nlet set = new TreeSet(comparator);\n\nset.add(1.2);\nset.add(2.3);\nset.add(33.4);\nset.add(4.55);\nset.add(2);\n\nfor(let entry in set){\n   println(entry);\n}\n```\n\n## Tools\n\nTo be productive in any language there needs to be a way to write, evalute and debug applications. The development \nenvironment is free to use and can be used in any standard web browser supporting HTML 5. Alternatively this \ndevelopment client can be run as a standalone application.\n\n### Command Line Interpreter\n\nTo run scripts as a standalone application you can download the interpreter. The interpreter requires Java to \nbe installed on the host machine. Once you have downloaded the interpreter you can begin running scripts right \naway. All you need to do is specify the script file relative to the current directory.\n\nDownload - [http://www.snapscript.org/download/snap.zip](http://www.snapscript.org/download/snap.zip)\n\n### Development Environment\n\nThe development environment, Snap Studio, is written with HTML5 and TypeScript. It comes packaged as a standalone application \nleveraging the [Chrome Embedded Framework](https://en.wikipedia.org/wiki/Chromium_Embedded_Framework). Running an application from Snap Studio is as simple has pressing the \nplay button. This will initiate a bootstrapping process where the interpreter is downloaded in to a harness once\nthis bootstrapping process has completed the source program is downloaded and executed. Stepping through the\ncode can be done by setting break points.\n\nDownload - [http://www.snapscript.org/download/snapd.zip](http://www.snapscript.org/download/snapd.zip)\n\n#### Breakpoints\n\nA breakpoint forces the debugger to suspend at a particular line when execution flow arrives at that line. Once\nsuspended the developer can step in, out or over the statements.\n\n![Developer Breakpoints](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_breakpoints.png)\n\n#### Console\n\nAll output from the application is captured in the console and displayed. This console is a scrolling window and\nwill keep only the most recent history up to a configurable number of lines.\n\n![Developer Console](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_console.png)\n\n#### Variables\n\nWhen execution is suspended it is possible to evaluate expressions and look at variables on the stack and in\nthe surrounding scope. These variables can be navigated by clicking through references.\n\n![Developer Variables](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_variables.png)\n\n#### Threads\n\nAt any time multiple threads may be suspended. A thread view is provided so that the developer can select the\nthread to debug and also to view the stack frames.\n\n![Developer Threads](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_threads.png)\n\n#### Process View\n\nIf there are multiple applications running from the development environment focus can only be given to one. It\nis possible to switch focus through the process view. Once focused an application can be debugged or terminated.\n\n![Developer Debug](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_agents.png)\n\n#### Debug Perspective\n\nTo capture as much relevant information on a single screen the debug perspectived can be used. This will allow\nthe developer to see the threads and variables as well as the console.\n\n![Developer Debug Perspective](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_changelayout.png)\n\n#### Full Screen\n\nWhen editing it can be useful to see the full screen. This perspective can be achieved by double clicking on\nthe tab in focus.\n\n![Developer Full Screen](https://raw.githubusercontent.com/snapscript/snap-site/master/images/debugger_fullscreen.png)\n\n### Debug Agent\n\nThe development environment can act as a debug service. As such it is possible to connect to a debugger and \npush code and debug information. To do this you simple need to embed the debug agent in to your application.\n\n### Android\n\nFull compatibility is provided for Android. A basic JIT is also provided to reduce the overhead of reflection\nand to allow types to be extended.\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapscript%2Fsnap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnapscript%2Fsnap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapscript%2Fsnap/lists"}