LangSpecs NameDefinitionAndLookup
Flatscript requires every name that is used is defined, either by statements that contains name defnitions, or extern
declarations. And a name is not allowed to defined or declared more than once in one scope.
This syntax will define a name, with its bound value.
name: bound_value
Once it is defined, its value (reference) could not be changed.
An enumeration statement is used to define multiple integer constant.
enum definition_list
where definition_list
is a comma-separated identifier list.
For example
enum WHITE, RED, GREEN, BLUE
is equivalent to define WHITE
as 0, RED
as 1, GREEN
as 2, and BLUE
as 3.
To define a function.
func function_name(parameter_list)
console.log('function_body')
where parameter_list
is a comma-separated identifier list, and at most one regular asynchoronous placeholder could be added to it.
The function name is available in the scope where it is defined, and each name in the its parameter list is available in the function body.
To define a class.
class class_name
ctor()
console.log('class body, constructor')
See detailed reference for class
definition.
Include another Flatscript source file as an available module.
include 'path/to/file' as module_name
See detailed reference for include
statement.
An extern
statement is used to declare names that are provided by other module. Usually this is useful in the browser environment.
extern identifier_list
where identifier_list
is a comma-separated identifier list.
For example
extern jQuery, moment
extern
statements are only allowed in the global scope. We suggest use them at the beginning of the file.
A for
-range declares a variable whose value changes each time. It could be used in the loop scope.
Flatscript naming scopes are bound with indentation. The outmost scope, who contains statements without indentation, is the global scope. There are many kind of other scopes, like for
-loop scope, if
-else
-branch scope, and func
tion body scope.
When Flatscript compile a scope and search for a name declaration, it will look up the current scope first, then outer scope, and then outer, until the global scope.
For example
baz: 123 # a
func foo(bar) # b
return bar + baz # c
when compile the return
statement at (c), the compiler will search for bar
and baz
. bar
is resolved as the local symbol from parameter list at (b), and baz
is resolved as the definition in the outer scope at (a).
Inner scope may define a name that is already defined in the outer scope. This will result in that the references to this name in the inner scope are resolved as the inner definition.
For example
bar: 123 # a
func foo(baz)
bar: 34 # b
return baz + bar # c
when compile the return
statement at (c), bar
is resolved as the local symbol defined at (b), not the outside definition at (a).
However, it is not allowed to define a name after it is referenced and probably resolved as an outer definition.
For example (compile error)
bar: 123 # a
func foo(baz)
fox: baz + bar # b
bar: 34 # c
bar
is used at (b) before it is defined at (c), and a compile error is emitted at (c). When compile (b), compiler resolves bar
as a reference to the outer definition, and therefore no error occurs at (b).
When Flatscript compile a scope, it will process names in this order
- register the class and function names
- compile the scope body
- compile class and function bodies
As a result
- a class or a function name is available in the entire scope no matter where it is located, even after a
return
orthrow
statement - a name defined locally could be referenced in the function or class bodies no matter where it is defined
Although Flatscript do some static name check, there are still some blind spots in those rules that compiler won't check at compile time.
For example, a name whose initial value is a function call that involves the name itself
bar: foo(10)
func foo(baz)
return bar + baz
There is no compile message for this code. However it results in bar
initialized as NaN
.