;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Sequential Definitions ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Sequential definitions is a pattern where definitions cannot be refered to ;; before they are defined, and definitions are shadowed by later definitions. ;; ;; These rules implement the following name binding behavior: ;; - Definitions are cannot be refered to before they are defined. ;; - Definitions are shadowed by later definitions in the same block. ;; ;; The supported Python syntax is: ;; - Top-level function definitions without parameters. ;; - Function calls without arguments. ;; - Pass statements. ;; - Comments. ;; ;; The following nodes are used: ;; - @node.lexical_scope nodes form a tree connecting "upwards" to the lexical ;; scope, and are used to resolve references in. ;; - @node.lexical_defs nodes are connected "downwards" to the definitions ;; introduced by statements. Lexical scopes are connected to them to make the ;; definitions available when resolving references. ;;;;;;;;;;;;;;;;;;;;;;; ;; Attribute Shorthands attribute node_definition = node => type = "pop_symbol", node_symbol = node, is_definition attribute node_reference = node => type = "push_symbol", node_symbol = node, is_reference attribute node_symbol = node => symbol = (source-text node), source_node = node ;;;;;;;;;; ;; Modules (module)@mod { node @mod.lexical_scope } (module (_)@left_stmt . (_)@right_stmt)@mod { ;; Every statements in the module can reach all definitions from previous statements in the module edge @right_stmt.lexical_scope -> @left_stmt.lexical_scope ;; The definitions from a statement are visible from the next statement on edge @right_stmt.lexical_scope -> @left_stmt.lexical_defs attr (@right_stmt.lexical_scope -> @left_stmt.lexical_defs) precedence = 1 } ;;;;;;;;;;;;; ;; Statements [ (expression_statement) (function_definition) (pass_statement) ]@stmt { node @stmt.lexical_scope node @stmt.lexical_defs } (expression_statement (_)@expr)@expr_stmt { ;; The expression can reach all definitions visible in the enclosing scope edge @expr.lexical_scope -> @expr_stmt.lexical_scope } (function_definition name:(identifier)@name)@fun_def { ;; A definition with the name @name is introduced node def attr (def) node_definition = @name ;; The definition is exposed to the surrounding block or module edge @fun_def.lexical_defs -> def } ;;;;;;;;;;;;;; ;; Expressions [ (call) ]@expr { node @expr.lexical_scope } (call function:(identifier)@name)@call_expr { ;; A reference for the name @name is introduced node ref attr (ref) node_reference = @name ;; The reference is resolved in the the enclosing scope edge ref -> @call_expr.lexical_scope } ;;;;;;;;;;; ;; Comments (comment)@comment { ;; Because comments can appear everywhere, we define all possible nodes on ;; them to prevent undefined errors node @comment.lexical_scope node @comment.lexical_defs }