Merit
Merit is a programming language that comes bundled with a Merideum implementation. Merideum uses Merit for request syntax and execution. The language is designed to be simple, concise, and familiar. Merit is intentionally unadvanced--this is to prevent misuse or abuse and keep requests and contracts from becoming too complex.
Script Definition
The script definition block goes first in a Merit script and contains the functionality of the script. The script definition contains the script type request or contract, the name of the script, and, depending on the script type, a list of parameters.
Request
A request definition does not have parameters.
request myRequest {
// the code goes in here
}
Contract
contract myContract {
// the code goes in here
}
A contract definition can have a list of parameters. A parameter has a name and a Merit type.
contract myParametizedContract(name: string, birthYear: int) {
// ...
}
Variables
A variable is either a const or a var.
const
A const variable cannot be reassigned. The request will fail and an error will be returned if a const variable is attempted to be reassigned.
const name = "Merideum"
A type declaration is only necessary if the value of the variable is set to null at declaration. Otherwise, the type is inferred from the value of the assignment.
const test: string? = null
var
A var variable can be reassigned.
var age = 24
age = 25
A var variable may also be declared without an assignment, but the type declaration is then required.
var age: int
age = 24
A type declaration is also required if the value would be null at declaration and assignment.
var test: string? = null
The type of the reassigned value must match the original type of the variable. The request will fail and an error will be returned if a variable is attempted to be reassigned with a value of a different type.
As Expression
A variable may be used in an expression.
const name = "Merideum"
const message = "Hello ${name}!"
Types
int
A 32-bit signed integer.
var age: int = 24
age = 25
string
A string of characters.
var name: string
name = "Merideum"
The length() function can be used to return the int length of a string.
const name = "Merideum"
const nameLength = name.length()
object
An object is a collection of key/value pair properties. Values are accessed through dot-notation or indexed notation using its key.
const car = {
color = "red",
doors = 4
}
const carColor = car.color
const carDoors = car["doors"]
If the value of the field is a variable reference and the name would match, there is a shorthand assignment:
color = "red"
const car = {
color,
doors = 4
}
Values can be added or removed to the object.
var car = {
color = "red",
doors = 4
}
car.driver = "Foo"
Just like with variables, a nullable value must have a type during declaration.
const car = {
color = "red",
doors = 4,
gas = 100,
driver: string? = null
}
A "sub-object" may be returned using the splice notation:
const person = {
firstName = "Foo",
lastName = "Bar",
age = 24
}
const nameOnly = person{ firstName, lastName }
If the field is an object, splicing may be performed on that field, and so on with its fields.
const person = {
firstName = "Foo",
lastName = "Bar",
age = 24,
location = {
city = "New York"
coords = {
geo = 2949034.39
lat = 320309.33
long = 856830.04
}
}
}
return person{
firstName,
lastName,
location{
city,
coords{
geo
}
}
}
Nullability
Variables are non-nullable by default. ? is used as part of the type declaration to denote a variable as nullable.
If a nullable variable would be set to null at declaration, the type declaration must be included.
const test: string? = null
var test2: string?
test2 = null
request object
The request object is a reserved variable that contains contextual attributes of the request (headers, auth, etc.) and is used to send non-output attributes on the response (headers, errors, etc). request cannot be assigned to another variable or used in an expression (but its properties or function results can).
errors
errors is a mutable object that will return on the response body if populated. These errors show up under errors.request.
Usage:
request.errors["idNotFound"] = "The ID was not found."
Response body (in json):
{
"errors": {
"request": {
"idNotFound": "The ID was not found."
}
}
}
fail()
The fail() function is used to stop the code execution immediately and return any errors. Since execution is stopped immediately, the fail() function does not return a value.
Usage:
request myRequest {
request.fail()
const message = "This will not run"
}
In contracts
In a contract the request object is instead named contract but it is functionally equivalent.
contract myContract(name: string) {
if (name == "bad") {
contract.errors["badName"] = "The name ${name} is bad"
contract.fail()
}
}
return
The return keyword is used to stop execution successfully and return an output value on the response body.
Usage:
request myRequest {
return { message = "Hello World!" }
const message = "This will not run"
}
Response body (in json):
{
"output": {
"message": "Hello World!"
}
}
If the value of the return is not an object, then the value is wrapped in an object with the field name value.
request myRequest {
return "Hello World!"
}
Response body (in json):
{
"output": {
"value": "Hello World!"
}
}
Resources
Resources are objects with functions that allow a Merit script to call code external to the script.
import
A resource is referenced by a dot-delimited path and its name and assigned to a variable using the import keyword. import statements must occur after the script definition and before any other statements. A resource name starts with a capital letter. A resource cannot be assigned to another variable.
request myRequest {
import greeter: org.merideum.Greeter
}
Import statements can be folded into an import block.
request myRequest {
import personRepository: org.person.PersonRepository
import locationService: org.location.LocationService
import calendar: com.google.Calendar
}
can be written as:
request myRequest {
import {
personRepository: org.person.PersonRepository
locationService: org.location.LocationService
calendar: com.google.Calendar
}
}
Functions
A resource function may have parameters and return a value:
request myRequest {
import greeter: org.merideum.Greeter
const name = "Merideum"
const message = greeter.sayHello(name)
}