Skip to content

LangSpecs NameDefinitionAndLookup

Neuron Teckid edited this page Mar 9, 2017 · 1 revision

Name Definition and Lookup

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.

Definition

Name Definition Statement

This syntax will define a name, with its bound value.

name: bound_value

Once it is defined, its value (reference) could not be changed.

Enumeration Statement

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.

Function Definition

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.

Class Definition

To define a class.

class class_name
    ctor()
        console.log('class body, constructor')

See detailed reference for class definition.

Include Statement

Include another Flatscript source file as an available module.

include 'path/to/file' as module_name

See detailed reference for include statement.

External Declaration

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.

For Loop

A for-range declares a variable whose value changes each time. It could be used in the loop scope.

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 function body scope.

Name Lookup

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).

Name Shadowing

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).

Cross Reference

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 or throw 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.