#include "ir.h"
void
-_mesa_generate_hir_from_ast(struct _mesa_glsl_parse_state *state)
+_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
{
struct simple_node *ptr;
+ _mesa_glsl_initialize_variables(instructions, state);
+
foreach (ptr, & state->translation_unit) {
- if (1) {
- }
+ ((ast_node *)ptr)->hir(instructions, state);
}
}
* * The two operands are scalars. In this case the operation is
* applied, resulting in a scalar."
*/
- if (is_glsl_type_scalar(type_a) && is_glsl_type_scalar(type_b))
+ if (type_a->is_scalar() && type_b->is_scalar())
return type_a;
/* "* One operand is a scalar, and the other is a vector or matrix.
* component of the vector or matrix, resulting in the same size
* vector or matrix."
*/
- if (is_glsl_type_scalar(type_a)) {
- if (!is_glsl_type_scalar(type_b))
+ if (type_a->is_scalar()) {
+ if (!type_b->is_scalar())
return type_b;
- } else if (is_glsl_type_scalar(type_b)) {
+ } else if (type_b->is_scalar()) {
return type_a;
}
* operation is done component-wise resulting in the same size
* vector."
*/
- if (is_glsl_type_vector(type_a) && is_glsl_type_vector(type_b)) {
+ if (type_a->is_vector() && type_b->is_vector()) {
if (type_a->vector_elements == type_b->vector_elements)
return type_a;
else
* more detail how vectors and matrices are operated on."
*/
if (! multiply) {
- if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b)
+ if (type_a->is_matrix() && type_b->is_matrix()
&& (type_a->vector_elements == type_b->vector_elements)
&& (type_a->matrix_rows == type_b->matrix_rows))
return type_a;
else
return glsl_error_type;
} else {
- if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b)) {
+ if (type_a->is_matrix() && type_b->is_matrix()) {
if (type_a->vector_elements == type_b->matrix_rows) {
char type_name[7];
const struct glsl_type *t;
type_name[6] = '\0';
}
- t = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
+ t = (glsl_type *)
+ _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
return (t != NULL) ? t : glsl_error_type;
}
- } else if (is_glsl_type_matrix(type_a)) {
+ } else if (type_a->is_matrix()) {
/* A is a matrix and B is a column vector. Columns of A must match
* rows of B.
*/
if (type_a->vector_elements == type_b->vector_elements)
return type_b;
} else {
- assert(is_glsl_type_matrix(type_b));
+ assert(type_b->is_matrix());
/* A is a row vector and B is a matrix. Columns of A must match
* rows of B.
* wise to the vector, resulting in the same type as the vector. If both
* are vectors of the same size, the result is computed component-wise."
*/
- if (is_glsl_type_vector(type_a)) {
- if (!is_glsl_type_vector(type_b)
+ if (type_a->is_vector()) {
+ if (!type_b->is_vector()
|| (type_a->vector_elements == type_b->vector_elements))
return type_a;
} else
*/
if (! is_numeric_base_type(type_a->base_type)
|| ! is_numeric_base_type(type_b->base_type)
- || ! is_glsl_type_scalar(type_a)
- || ! is_glsl_type_scalar(type_b))
+ || !type_a->is_scalar()
+ || !type_b->is_scalar())
return glsl_error_type;
/* "Either the operands' types must match, or the conversions from
}
-struct ir_instruction *
-ast_expression_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_node::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ (void) instructions;
+ (void) state;
+
+ return NULL;
+}
+
+
+ir_instruction *
+ast_expression::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_expression *expr =
- (struct ast_expression *) ast;
static const int operations[AST_NUM_OPERATORS] = {
-1, /* ast_assign doesn't convert to ir_expression. */
-1, /* ast_plus doesn't convert to ir_expression. */
-1, /* ast_bool_constant doesn't conv to ir_expression. */
-1, /* ast_sequence doesn't convert to ir_expression. */
};
- struct ir_instruction *result = NULL;
- struct ir_instruction *op[2];
+ ir_instruction *result = NULL;
+ ir_instruction *op[2];
struct simple_node op_list;
const struct glsl_type *type = glsl_error_type;
bool error_emitted = false;
YYLTYPE loc;
- loc = ast->get_location();
+ loc = this->get_location();
make_empty_list(& op_list);
- switch (expr->oper) {
- case ast_assign:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
- op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+ switch (this->oper) {
+ case ast_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
error_emitted = ((op[0]->type == glsl_error_type)
|| (op[1]->type == glsl_error_type));
YYLTYPE loc;
/* FINISHME: This does not handle 'foo.bar.a.b.c[5].d = 5' */
- loc = expr->subexpressions[0]->get_location();
+ loc = this->subexpressions[0]->get_location();
if (op[0]->mode != ir_op_dereference) {
_mesa_glsl_error(& loc, state, "invalid lvalue in assignment");
error_emitted = true;
/* FINISHME: Check that the LHS and RHS have matching types. */
/* FINISHME: For GLSL 1.10, check that the types are not arrays. */
- result = new ir_assignment(op[0], op[1], NULL);
+ ir_instruction *tmp = new ir_assignment(op[0], op[1], NULL);
+ instructions->push_tail(tmp);
+
+ result = op[0];
break;
+ }
case ast_plus:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
error_emitted = (op[0]->type == glsl_error_type);
if (type == glsl_error_type)
break;
case ast_neg:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
type = unary_arithmetic_result_type(op[0]->type);
error_emitted = (op[0]->type == glsl_error_type);
- result = new ir_expression(operations[expr->oper], type,
+ result = new ir_expression(operations[this->oper], type,
op[0], NULL);
break;
case ast_sub:
case ast_mul:
case ast_div:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
- op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
type = arithmetic_result_type(op[0]->type, op[1]->type,
- (expr->operr == ast_mul),
+ (this->oper == ast_mul),
state);
- result = new ir_expression(operations[expr->oper], type,
+ result = new ir_expression(operations[this->oper], type,
op[0], op[1]);
break;
case ast_mod:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
- op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
error_emitted = ((op[0]->type == glsl_error_type)
|| (op[1]->type == glsl_error_type));
type = modulus_result_type(op[0]->type, op[1]->type);
- assert(operations[expr->oper] == ir_binop_mod);
+ assert(operations[this->oper] == ir_binop_mod);
- result = new ir_expression(operations[expr->oper], type,
+ result = new ir_expression(operations[this->oper], type,
op[0], op[1]);
break;
case ast_greater:
case ast_lequal:
case ast_gequal:
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
- op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
error_emitted = ((op[0]->type == glsl_error_type)
|| (op[1]->type == glsl_error_type));
*/
assert((type == glsl_error_type)
|| ((type->base_type == GLSL_TYPE_BOOL)
- && is_glsl_type_scalar(type)));
+ && type->is_scalar()));
- result = new ir_expression(operations[expr->oper], type,
+ result = new ir_expression(operations[this->oper], type,
op[0], op[1]);
break;
case ast_sub_assign: {
struct ir_instruction *temp_rhs;
- op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
- op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
error_emitted = ((op[0]->type == glsl_error_type)
|| (op[1]->type == glsl_error_type));
type = arithmetic_result_type(op[0]->type, op[1]->type,
- (expr->oper == ast_mul_assign),
+ (this->oper == ast_mul_assign),
state);
- temp_rhs = new ir_expression(operations[expr->oper], type,
+ temp_rhs = new ir_expression(operations[this->oper], type,
op[0], op[1]);
/* FINISHME: Check that the LHS is assignable. */
break;
case ast_field_selection:
- result = _mesa_ast_field_selection_to_hir(expr, instructions, state);
+ result = _mesa_ast_field_selection_to_hir(this, instructions, state);
type = result->type;
break;
break;
case ast_function_call:
- /* There are three sorts of function calls.
- *
- * 1. contstructors - The first subexpression is an ast_type_specifier.
- * 2. methods - Only the .length() method of array types.
- * 3. functions - Calls to regular old functions.
- *
- * Method calls are actually detected when the ast_field_selection
- * expression is handled.
+ /* Should *NEVER* get here. ast_function_call should always be handled
+ * by ast_function_expression::hir.
*/
- result = _mesa_ast_function_call_to_hir(expr->subexpressions[0],
- expr->subexpressions[1],
- state);
- type = result->type;
+ assert(0);
break;
case ast_identifier: {
* tree. This particular use must be at location specified in the grammar
* as 'variable_identifier'.
*/
- struct ir_variable *var =
+ ir_variable *var = (ir_variable *)
_mesa_symbol_table_find_symbol(state->symbols, 0,
- expr->primary_expression.identifier);
+ this->primary_expression.identifier);
result = new ir_dereference(var);
type = result->type;
} else {
_mesa_glsl_error(& loc, NULL, "`%s' undeclared",
- expr->primary_expression.identifier);
+ this->primary_expression.identifier);
error_emitted = true;
}
case ast_int_constant:
type = glsl_int_type;
- result = new ir_constant(type, & expr->primary_expression);
+ result = new ir_constant(type, & this->primary_expression);
break;
case ast_uint_constant:
type = glsl_uint_type;
- result = new ir_constant(type, & expr->primary_expression);
+ result = new ir_constant(type, & this->primary_expression);
break;
case ast_float_constant:
type = glsl_float_type;
- result = new ir_constant(type, & expr->primary_expression);
+ result = new ir_constant(type, & this->primary_expression);
break;
case ast_bool_constant:
type = glsl_bool_type;
- result = new ir_constant(type, & expr->primary_expression);
+ result = new ir_constant(type, & this->primary_expression);
break;
case ast_sequence: {
/* It should not be possible to generate a sequence in the AST without
* any expressions in it.
*/
- assert(!is_empty_list(&expr->expressions));
+ assert(!is_empty_list(&this->expressions));
/* The r-value of a sequence is the last expression in the sequence. If
* the other expressions in the sequence do not have side-effects (and
* therefore add instructions to the instruction list), they get dropped
* on the floor.
*/
- foreach (ptr, &expr->expressions)
- result = _mesa_ast_to_hir(ptr, instructions, state);
+ foreach (ptr, &this->expressions)
+ result = ((ast_node *)ptr)->hir(instructions, state);
type = result->type;
}
-struct ir_instruction *
-ast_expression_statement_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_function_expression::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_expression_statement *stmt =
- (struct ast_expression_statement *) ast;
+ /* There are three sorts of function calls.
+ *
+ * 1. contstructors - The first subexpression is an ast_type_specifier.
+ * 2. methods - Only the .length() method of array types.
+ * 3. functions - Calls to regular old functions.
+ *
+ * Method calls are actually detected when the ast_field_selection
+ * expression is handled.
+ */
+ (void) instructions;
+ (void) state;
+ return ir_call::get_error_instruction();
+}
+ir_instruction *
+ast_expression_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
/* It is possible to have expression statements that don't have an
* expression. This is the solitary semicolon:
*
* In this case the expression will be NULL. Test for NULL and don't do
* anything in that case.
*/
- if (stmt->expression != NULL)
- _mesa_ast_to_hir(stmt->expression, instructions, state);
+ if (expression != NULL)
+ expression->hir(instructions, state);
/* Statements do not have r-values.
*/
}
-struct ir_instruction *
-ast_compound_statement_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_compound_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_compound_statement *stmt =
- (struct ast_compound_statement *) ast;
struct simple_node *ptr;
- if (stmt->new_scope)
+ if (new_scope)
_mesa_symbol_table_push_scope(state->symbols);
- foreach (ptr, &stmt->statements)
- _mesa_ast_to_hir(ptr, instructions, state);
+ foreach (ptr, &statements)
+ ((ast_node *)ptr)->hir(instructions, state);
- if (stmt->new_scope)
+ if (new_scope)
_mesa_symbol_table_pop_scope(state->symbols);
/* Compound statements do not have r-values.
type_name = (spec->type_specifier == ast_type_name)
? spec->type_name : type_names[spec->type_specifier];
- type = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
+ type = (glsl_type *)
+ _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
*name = type_name;
/* FINISHME: Handle array declarations. Note that this requires complete
else if (qual->attribute || qual->in
|| (qual->varying && (state->target == fragment_shader)))
var->mode = ir_var_in;
- else if (qual->out)
+ else if (qual->out || (qual->varying && (state->target == vertex_shader)))
var->mode = ir_var_out;
else if (qual->uniform)
var->mode = ir_var_uniform;
}
-struct ir_instruction *
-ast_declarator_list_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_declarator_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_declarator_list *dlist = (struct ast_declarator_list *) ast;
struct simple_node *ptr;
const struct glsl_type *decl_type;
const char *type_name = NULL;
* FINISHME: invariant.
*/
- decl_type = type_specifier_to_glsl_type(dlist->type->specifier,
+ decl_type = type_specifier_to_glsl_type(this->type->specifier,
& type_name, state);
- foreach (ptr, &dlist->declarations) {
+ foreach (ptr, &this->declarations) {
struct ast_declaration *const decl = (struct ast_declaration * )ptr;
const struct glsl_type *var_type;
struct ir_variable *var;
if (decl_type == NULL) {
YYLTYPE loc;
- loc = ast->get_location();
+ loc = this->get_location();
if (type_name != NULL) {
_mesa_glsl_error(& loc, state,
"invalid type `%s' in declaration of `%s'",
* FINISHME: in a parameter list (in and out only).
*/
- apply_type_qualifier_to_variable(& dlist->type->qualifier, var, state);
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state);
/* Attempt to add the variable to the symbol table. If this fails, it
* means the variable has already been declared at this scope.
*/
if (_mesa_symbol_table_add_symbol(state->symbols, 0, decl->identifier,
var) != 0) {
- YYLTYPE loc = ast->get_location();
+ YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state, "`%s' redeclared",
decl->identifier);
continue;
}
- insert_at_tail(instructions, (struct simple_node *) var);
+ instructions->push_tail(var);
/* FINISHME: Process the declaration initializer. */
}
}
-struct ir_instruction *
-ast_parameter_declarator_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_parameter_declarator::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_parameter_declarator *decl =
- (struct ast_parameter_declarator *) ast;
- struct ir_variable *var;
const struct glsl_type *type;
const char *name = NULL;
- type = type_specifier_to_glsl_type(decl->type->specifier, & name, state);
+ type = type_specifier_to_glsl_type(this->type->specifier, & name, state);
if (type == NULL) {
- YYLTYPE loc = ast->get_location();
+ YYLTYPE loc = this->get_location();
if (name != NULL) {
_mesa_glsl_error(& loc, state,
"invalid type `%s' in declaration of `%s'",
- name, decl->identifier);
+ name, this->identifier);
} else {
_mesa_glsl_error(& loc, state,
"invalid type in declaration of `%s'",
- decl->identifier);
+ this->identifier);
}
type = glsl_error_type;
}
- var = new ir_variable(type, decl->identifier);
+ ir_variable *var = new ir_variable(type, this->identifier);
/* FINISHME: Handle array declarations. Note that this requires
* FINISHME: complete handling of constant expressions.
*/
- apply_type_qualifier_to_variable(& decl->type->qualifier, var, state);
+ /* Apply any specified qualifiers to the parameter declaration. Note that
+ * for function parameters the default mode is 'in'.
+ */
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state);
+ if (var->mode == ir_var_auto)
+ var->mode = ir_var_in;
- insert_at_tail(instructions, var);
+ instructions->push_tail(var);
/* Parameter declarations do not have r-values.
*/
static void
ast_function_parameters_to_hir(struct simple_node *ast_parameters,
- struct simple_node *ir_parameters,
+ exec_list *ir_parameters,
struct _mesa_glsl_parse_state *state)
{
struct simple_node *ptr;
foreach (ptr, ast_parameters) {
- _mesa_ast_to_hir(ptr, ir_parameters, state);
+ ((ast_node *)ptr)->hir(ir_parameters, state);
}
}
static bool
-parameter_lists_match(struct simple_node *list_a, struct simple_node *list_b)
+parameter_lists_match(exec_list *list_a, exec_list *list_b)
{
- struct simple_node *node_a;
- struct simple_node *node_b;
+ exec_list_iterator iter_a = list_a->iterator();
+ exec_list_iterator iter_b = list_b->iterator();
- node_b = first_elem(list_b);
- foreach (node_a, list_a) {
+ while (iter_a.has_next()) {
/* If all of the parameters from the other parameter list have been
* exhausted, the lists have different length and, by definition,
* do not match.
*/
- if (at_end(list_b, node_b))
+ if (!iter_b.has_next())
return false;
/* If the types of the parameters do not match, the parameters lists
/* FINISHME */
- node_b = next_elem(node_b);
+ iter_a.next();
+ iter_b.next();
}
return true;
}
-struct ir_instruction *
-ast_function_definition_to_hir(const struct ast_node *ast,
- struct simple_node *instructions,
- struct _mesa_glsl_parse_state *state)
+ir_instruction *
+ast_function_definition::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
- const struct ast_function_definition *func =
- (struct ast_function_definition *) ast;
- struct ir_label *label;
- struct simple_node *ptr;
- struct simple_node *tmp;
- struct ir_function_signature *signature = NULL;
- struct ir_function *f = NULL;
- struct simple_node parameters;
+ ir_label *label;
+ ir_function_signature *signature = NULL;
+ ir_function *f = NULL;
+ exec_list parameters;
/* Convert the list of function parameters to HIR now so that they can be
* used below to compare this function's signature with previously seen
* signatures for functions with the same name.
*/
- make_empty_list(& parameters);
- ast_function_parameters_to_hir(& func->prototype->parameters, & parameters,
+ ast_function_parameters_to_hir(& this->prototype->parameters, & parameters,
state);
* seen signature for a function with the same name, or, if a match is found,
* that the previously seen signature does not have an associated definition.
*/
- f = _mesa_symbol_table_find_symbol(state->symbols, 0,
- func->prototype->identifier);
+ f = (ir_function *)
+ _mesa_symbol_table_find_symbol(state->symbols, 0,
+ this->prototype->identifier);
if (f != NULL) {
- foreach (ptr, & f->signatures) {
- signature = (struct ir_function_signature *) ptr;
+ foreach_iter(exec_list_iterator, iter, f->signatures) {
+ signature = (struct ir_function_signature *) iter.get();
/* Compare the parameter list of the function being defined to the
* existing function. If the parameter lists match, then the return
/* FINISHME: Compare return types. */
if (signature->definition != NULL) {
- YYLTYPE loc = ast->get_location();
+ YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state, "function `%s' redefined",
- func->prototype->identifier);
+ this->prototype->identifier);
signature = NULL;
break;
}
} else {
f = new ir_function();
- f->name = func->prototype->identifier;
+ f->name = this->prototype->identifier;
_mesa_symbol_table_add_symbol(state->symbols, 0, f->name, f);
}
*/
if (signature == NULL) {
signature = new ir_function_signature();
- insert_at_tail(& f->signatures, (struct simple_node *) signature);
+ f->signatures.push_tail(signature);
} else {
/* Destroy all of the previous parameter information. The previous
* parameter information comes from the function prototype, and it can
* either include invalid parameter names or may not have names at all.
*/
- foreach_s(ptr, tmp, & signature->parameters) {
- assert(((struct ir_instruction *)ptr)->mode == ir_op_var_decl);
+ foreach_iter(exec_list_iterator, iter, signature->parameters) {
+ assert(((struct ir_instruction *)iter.get())->mode == ir_op_var_decl);
- remove_from_list(ptr);
- free(ptr);
+ iter.remove();
+ delete iter.get();
}
}
- ast_function_parameters_to_hir(& func->prototype->parameters,
+ ast_function_parameters_to_hir(& this->prototype->parameters,
& signature->parameters,
state);
/* FINISHME: Set signature->return_type */
- label = new ir_label(func->prototype->identifier);
+ label = new ir_label(this->prototype->identifier);
if (signature->definition == NULL) {
signature->definition = label;
}
- insert_at_tail(instructions, label);
+ instructions->push_tail(label);
/* Add the function parameters to the symbol table. During this step the
* parameter declarations are also moved from the temporary "parameters" list
* but they involve ugly linked-list gymnastics.
*/
_mesa_symbol_table_push_scope(state->symbols);
- foreach_s(ptr, tmp, & parameters) {
- struct ir_variable *const var = (struct ir_variable *) ptr;
+ foreach_iter(exec_list_iterator, iter, parameters) {
+ ir_variable *const var = (ir_variable *) iter.get();
- assert(var->mode == ir_op_var_decl);
+ assert(((ir_instruction *)var)->mode == ir_op_var_decl);
- remove_from_list(ptr);
- insert_at_tail(instructions, ptr);
+ iter.remove();
+ instructions->push_tail(var);
_mesa_symbol_table_add_symbol(state->symbols, 0, var->name, var);
}
* instructions to the list that currently consists of the function label
* and the function parameters.
*/
- _mesa_ast_to_hir(func->body, instructions, state);
+ this->body->hir(instructions, state);
_mesa_symbol_table_pop_scope(state->symbols);