-
Notifications
You must be signed in to change notification settings - Fork 28
Language reference
This document will evolve to eventually be a complete language reference, with a formal grammar definition. For this early release, it will remain an informal yet thorough coverage of the language's syntax and features.
The source code files must be encoded in UTF-8.
Agora supports two forms of comments:
- Line comments start with
//and end at the end of the line - Block comments start with
/*and end at the next*/
Statements are terminated with a semicolon, but the may be omitted in the source code. The scanner stage of the compiler automatically inserts the semicolons if the last token on the line is:
- an identifier
- a literal value
- one of the keywords
return,debug,breakorcontinue - one of
++,--,),]or}
An identifier is a sequence of letters, underscores and numbers. It must start with a letter.
The following identifiers are keywords in the language and may not be used as identifiers:
- if
- else
- for
- func
- return
- debug
- break
- continue
Additionally, the following identifiers are reserved and may not be used as variables:
- true
- false
- nil
- import
- panic
- recover
- len
- this
- args
The following symbols represent operators and delimiters in the language:
- ( ) [ ] { }
- . , ; :
-
-
-
- / % ! && || ?
-
-
- == != < <= > >=
- = := += -= *= /= %=
- ++ --
Number literals can be represented as integers or floats. At the moment there is an inconsistency between what is accepted by the compiler and what can be used. Only base-10 notation should be used for now, i.e. 42, and floating-points should use the integer-decimal point-fraction notationm i.e. 3.1415.
At the moment there is an inconsistency between what is accepted by the compiler and what can be used. Only string literals within double quotes should be used, i.e. "this is a string". It may not contain newlines, but escape characters can be used (i.e. \n for newline).
Booleans are represented with the true and false literal values.
The nil value is represented with nil.
Objects are represented using the {key: value, otherkey: value} notation, which may be used recursively.
A function prototype is introduced using the func keyword. It can be used as a statement and as an expression:
// Statement
func myFunc() { return "statement" }
// Expression
myVar := func() { return "expression" }
In statement form, the "name" of the function is in fact a variable in the scope of the parent of the function being declared. The above example is equivalent to this:
myFunc := func() { return "statement" }
The expression form is self-explanatory.
Functions are first-class values and can be stored in variables and passed around in function arguments and return values, or in object fields. It is possible to declare a function within a function, although closures are not supported at the moment (returning a function from a function will not close over the variables of the parent function). This is a feature that will be added eventually.
Functions declare expected arguments by giving a list of identifiers within the parentheses of its definition. It can't declare a return value variable. Functions always return a single value, which is nil if there is no explicitly returned value.
func Add(x, y) {
return x + y
}
Functions may receive more or less arguments than expected. In the former case, the extra argument variables have the nil value. In the latter case, the extra arguments can be retrieved via the args reserved identifier, which is an array-like object that holds all arguments passed to the function, at keys 0 to len(args)-1.
If the function was assigned to an object's field, and was called with the object notation, then its this reserved identifier is set to the object.
obj := {name: "Martin"}
obj.MyFunc = func() {
return this.name
}
obj.MyFunc()
If the same function is stored in a variable and called not with the object notation, the this identifier is nil.
noThis := obj.MyFunc
noThis() // Error
All variables are declared in the scope of the function where they are defined, using the := operator, or the arguments and function names. All module-level variables are scoped in the top-level function (the module).