Skip to content

Commit

Permalink
issue #35 more fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dibyendumajumdar committed Oct 3, 2020
1 parent 7b2af91 commit 0f4f01a
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 56 deletions.
7 changes: 6 additions & 1 deletion src/ast_printer.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ static void print_symbol_name(buffer_t *buf, struct lua_symbol *sym)
break;
}
case SYM_UPVALUE: {
printf_buf(buf, "%t", sym->upvalue.target_variable->variable.var_name);
if (sym->upvalue.target_variable->symbol_type == SYM_ENV) {
printf_buf(buf, "%t*", sym->upvalue.target_variable->variable.var_name);
}
else {
printf_buf(buf, "%t", sym->upvalue.target_variable->variable.var_name);
}
break;
}
default:
Expand Down
23 changes: 12 additions & 11 deletions src/ast_walker.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,7 @@ bool raviX_function_statement_is_method(const struct function_statement *stateme
}
const struct index_expression *raviX_function_statement_method_name(const struct function_statement *statement)
{
assert(statement->method_name->type == EXPR_Y_INDEX ||
statement->method_name->type == EXPR_FIELD_SELECTOR);
assert(statement->method_name->type == EXPR_Y_INDEX || statement->method_name->type == EXPR_FIELD_SELECTOR);
return &statement->method_name->index_expr;
}
bool raviX_function_statement_has_selectors(const struct function_statement *statement)
Expand Down Expand Up @@ -469,14 +468,12 @@ const struct var_type *raviX_binary_expression_type(const struct binary_expressi
}
const struct expression *raviX_binary_expression_left_expression(const struct binary_expression *expression)
{
assert(expression->expr_left->type >= EXPR_LITERAL &&
expression->expr_left->type <= EXPR_FUNCTION_CALL);
assert(expression->expr_left->type >= EXPR_LITERAL && expression->expr_left->type <= EXPR_FUNCTION_CALL);
return (const struct expression *)expression->expr_left;
}
const struct expression *raviX_binary_expression_right_expression(const struct binary_expression *expression)
{
assert(expression->expr_right->type >= EXPR_LITERAL &&
expression->expr_right->type <= EXPR_FUNCTION_CALL);
assert(expression->expr_right->type >= EXPR_LITERAL && expression->expr_right->type <= EXPR_FUNCTION_CALL);
return (const struct expression *)expression->expr_right;
}
BinaryOperatorType raviX_binary_expression_operator(const struct binary_expression *expression)
Expand All @@ -499,8 +496,7 @@ raviX_table_element_assignment_expression_key(const struct table_element_assignm
const struct expression *
raviX_table_element_assignment_expression_value(const struct table_element_assignment_expression *expression)
{
assert(expression->value_expr->type >= EXPR_LITERAL &&
expression->value_expr->type <= EXPR_FUNCTION_CALL);
assert(expression->value_expr->type >= EXPR_LITERAL && expression->value_expr->type <= EXPR_FUNCTION_CALL);
return (const struct expression *)expression->value_expr;
}
const struct var_type *raviX_table_literal_expression_type(const struct table_literal_expression *expression)
Expand All @@ -526,8 +522,7 @@ const struct var_type *raviX_suffixed_expression_type(const struct suffixed_expr
}
const struct expression *raviX_suffixed_expression_primary(const struct suffixed_expression *expression)
{
assert(expression->primary_expr->type >= EXPR_LITERAL &&
expression->primary_expr->type <= EXPR_FUNCTION_CALL);
assert(expression->primary_expr->type >= EXPR_LITERAL && expression->primary_expr->type <= EXPR_FUNCTION_CALL);
return (const struct expression *)expression->primary_expr;
}
void raviX_suffixed_expression_foreach_suffix(const struct suffixed_expression *expression, void *userdata,
Expand Down Expand Up @@ -603,13 +598,19 @@ const struct var_type *raviX_upvalue_symbol_type(const struct lua_upvalue_symbol
}
const struct lua_variable_symbol *raviX_upvalue_target_variable(const struct lua_upvalue_symbol *symbol)
{
if (symbol->target_variable->symbol_type == SYM_ENV) {
assert(symbol->target_function == NULL);
return NULL;
}
assert(symbol->target_variable->symbol_type == SYM_LOCAL);
return &symbol->target_variable->variable;
}
const struct function_expression *raviX_upvalue_target_function(const struct lua_upvalue_symbol *symbol)
{
if (symbol->target_variable->symbol_type == SYM_ENV)
if (symbol->target_variable->symbol_type == SYM_ENV) {
assert(symbol->target_function == NULL);
return NULL;
}
assert(symbol->target_function->type == EXPR_FUNCTION);
return &symbol->target_function->function_expr;
}
Expand Down
105 changes: 62 additions & 43 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,16 @@ static void add_ast_node(struct compiler_state *container, struct ast_node_list
ptrlist_add((struct ptr_list **)list, node, &container->ptrlist_allocator);
}

static struct ast_node *allocate_ast_node(struct parser_state *parser, enum ast_node_type type) {
static struct ast_node *allocate_ast_node(struct parser_state *parser, enum ast_node_type type)
{
struct ast_node *node = (struct ast_node *)raviX_allocator_allocate(&parser->container->ast_node_allocator, 0);
node->type = type;
node->line_number = parser->ls->lastline;
return node;
}

static struct ast_node *allocate_expr_ast_node(struct parser_state *parser, enum ast_node_type type) {
static struct ast_node *allocate_expr_ast_node(struct parser_state *parser, enum ast_node_type type)
{
struct ast_node *node = allocate_ast_node(parser, type);
node->common_expr.truncate_results = 0;
set_typecode(&node->common_expr.type, RAVI_TANY);
Expand Down Expand Up @@ -210,7 +212,8 @@ static struct lua_symbol *search_upvalue_in_function(struct ast_node *function,
{
switch (symbol->symbol_type) {
case SYM_UPVALUE: {
assert(symbol->upvalue.target_variable->symbol_type == SYM_LOCAL || symbol->upvalue.target_variable->symbol_type == SYM_ENV);
assert(symbol->upvalue.target_variable->symbol_type == SYM_LOCAL ||
symbol->upvalue.target_variable->symbol_type == SYM_ENV);
if (name == symbol->upvalue.target_variable->variable.var_name) {
return symbol;
}
Expand All @@ -235,7 +238,8 @@ static bool add_upvalue_in_function(struct parser_state *parser, struct ast_node
{
switch (symbol->symbol_type) {
case SYM_UPVALUE: {
assert(symbol->upvalue.target_variable->symbol_type == SYM_LOCAL || symbol->upvalue.target_variable->symbol_type == SYM_ENV);
assert(symbol->upvalue.target_variable->symbol_type == SYM_LOCAL ||
symbol->upvalue.target_variable->symbol_type == SYM_ENV);
if (sym == symbol->upvalue.target_variable) {
return false;
}
Expand Down Expand Up @@ -301,6 +305,10 @@ static struct lua_symbol *search_for_variable(struct parser_state *parser, const
static void add_upvalue_in_levels_upto(struct parser_state *parser, struct ast_node *current_function,
struct ast_node *var_function, struct lua_symbol *symbol)
{
// NOTE: var_function may be NULL in the case of _ENV
// This is okay as it means we go up the whole call stack in that case
assert(symbol->symbol_type == SYM_LOCAL || symbol->symbol_type == SYM_ENV);
assert(symbol->symbol_type == SYM_ENV && var_function == NULL || var_function != NULL);
assert(current_function != var_function);
while (current_function && current_function != var_function) {
bool added = add_upvalue_in_function(parser, current_function, symbol);
Expand All @@ -312,28 +320,35 @@ static void add_upvalue_in_levels_upto(struct parser_state *parser, struct ast_n
}

/**
* Adds an upvalue for _ENV.
* Adds an upvalue for _ENV.
*/
static void add_upvalue_for_ENV(struct parser_state *parser)
{
// We have to check whether we need to add upvalue for _ENV
bool is_local = false;
struct lua_symbol *env = search_for_variable(parser, parser->container->_ENV, &is_local);
if (env == NULL) {
// Create special upvalue symbol _ENV - so that upvalues can reference it
struct lua_symbol *env = raviX_allocator_allocate(&parser->container->symbol_allocator, 0);
env->symbol_type = SYM_ENV;
env->variable.var_name = parser->container->_ENV;
env->variable.block = NULL;
set_type(&env->variable.value_type, RAVI_TTABLE); // _ENV is by default a table
// First time we encounter the global _ENV we add as upvalue
add_upvalue_in_levels_upto(parser, parser->current_function, NULL, env);
} else if (env->symbol_type == SYM_UPVALUE && env->upvalue.target_function != parser->current_function) {
struct lua_symbol *symbol = search_for_variable(parser, parser->container->_ENV, &is_local);
if (symbol == NULL) {
// No definition of _ENV found
// Create special symbol for _ENV - so that upvalues can reference it
// Note that this symbol is not added to any scope, however upvalue created below will reference it
symbol = raviX_allocator_allocate(&parser->container->symbol_allocator, 0);
symbol->symbol_type = SYM_ENV;
symbol->variable.var_name = parser->container->_ENV;
symbol->variable.block = NULL;
set_type(&symbol->variable.value_type, RAVI_TTABLE); // _ENV is by default a table
// Create an upvalue for _ENV
add_upvalue_in_levels_upto(parser, parser->current_function, NULL, symbol);
} else if (!is_local && symbol->symbol_type == SYM_LOCAL) {
// If _ENV occurred as a local symbol in a parent function then we
// need to construct an upvalue. Lua requires that the upvalue be
// added to all functions in the tree up to the function where the local
// is defined.
add_upvalue_in_levels_upto(parser, parser->current_function, symbol->variable.block->function, symbol);
} else if (symbol->symbol_type == SYM_UPVALUE && symbol->upvalue.target_function != parser->current_function) {
// We found an upvalue but it is not at the same level
// Ensure all levels have the upvalue
// Note that if the upvalue refers to special _ENV symbol then target function will be NULL
add_upvalue_in_levels_upto(parser, parser->current_function, env->upvalue.target_function,
env->upvalue.target_variable);
add_upvalue_in_levels_upto(parser, parser->current_function, symbol->upvalue.target_function,
symbol->upvalue.target_variable);
}
}

Expand All @@ -357,7 +372,8 @@ static struct ast_node *new_symbol_reference(struct parser_state *parser, const
symbol);
// TODO Following search could be avoided if above returned the symbol
symbol = search_upvalue_in_function(parser->current_function, varname);
} else if (symbol->symbol_type == SYM_UPVALUE && symbol->upvalue.target_function != parser->current_function) {
} else if (symbol->symbol_type == SYM_UPVALUE &&
symbol->upvalue.target_function != parser->current_function) {
// We found an upvalue but it is not at the same level
// Ensure all levels have the upvalue
// Note that if the uvalue refers to special _ENV symbol then target function will be NULL
Expand All @@ -376,7 +392,11 @@ static struct ast_node *new_symbol_reference(struct parser_state *parser, const
// We don't add globals to any scope so that they are
// always looked up
symbol = global;
add_upvalue_for_ENV(parser); // Since we have a global reference we need to add upvalue for _ENV
// Since we have a global reference we need to add upvalue for _ENV
// At the parser level we do not try to model that the global reference will be
// resolved by _ENV[name] - we leave that to the code generator to decide.
// However adding an upvalue later is hard so we do it here.
add_upvalue_for_ENV(parser);
}
struct ast_node *symbol_expr = allocate_expr_ast_node(parser, EXPR_SYMBOL);
symbol_expr->symbol_expr.type = symbol->variable.value_type;
Expand Down Expand Up @@ -477,7 +497,7 @@ static struct ast_node *parse_field(struct parser_state *parser)
struct lexer_state *ls = parser->ls;
/* field -> listfield | recfield */
switch (ls->t.token) {
case TOK_NAME: { /* may be 'listfield' or 'recfield' */
case TOK_NAME: { /* may be 'listfield' or 'recfield' */
if (raviX_lookahead(ls) != '=') /* expression? */
return parse_listfield(parser);
else
Expand All @@ -496,21 +516,20 @@ static struct ast_node *parse_field(struct parser_state *parser)
return NULL;
}

static struct ast_node* has_function_call(struct ast_node *expr)
static struct ast_node *has_function_call(struct ast_node *expr)
{
if (!expr)
return NULL;
if (expr->type == EXPR_FUNCTION_CALL)
return expr;
else if (expr->type == EXPR_SUFFIXED) {
if (expr->suffixed_expr.suffix_list) {
return has_function_call((struct ast_node *) ptrlist_last((struct ptr_list *) expr->suffixed_expr.suffix_list));
}
else {
return has_function_call(
(struct ast_node *)ptrlist_last((struct ptr_list *)expr->suffixed_expr.suffix_list));
} else {
return has_function_call(expr->suffixed_expr.primary_expr);
}
}
else {
} else {
return NULL;
}
}
Expand All @@ -520,14 +539,14 @@ static struct ast_node* has_function_call(struct ast_node *expr)
*/
static void set_multireturn(struct parser_state *parser, struct ast_node_list *expr_list, bool in_table_constructor)
{
struct ast_node *last_expr = (struct ast_node *) ptrlist_last((struct ptr_list *) expr_list);
struct ast_node *last_expr = (struct ast_node *)ptrlist_last((struct ptr_list *)expr_list);
if (!last_expr)
return;
if (in_table_constructor) {
if (last_expr->type == EXPR_TABLE_ELEMENT_ASSIGN && last_expr->table_elem_assign_expr.key_expr == NULL) {
if (last_expr->type == EXPR_TABLE_ELEMENT_ASSIGN &&
last_expr->table_elem_assign_expr.key_expr == NULL) {
last_expr = last_expr->table_elem_assign_expr.value_expr;
}
else {
} else {
return;
}
}
Expand Down Expand Up @@ -658,7 +677,7 @@ static bool parse_parameter_list(struct parser_state *parser, struct lua_symbol_
do {
switch (ls->t.token) {
case TOK_NAME: { /* param -> NAME */
/* RAVI change - add type */
/* RAVI change - add type */
struct lua_symbol *symbol = parse_local_variable_declaration(parser);
symbol->variable.function_parameter = 1;
add_symbol(parser->container, list, symbol);
Expand Down Expand Up @@ -1234,9 +1253,9 @@ static struct ast_node *parse_for_statement(struct parser_state *parser, int lin
stmt->for_stmt.expr_list = NULL;
stmt->for_stmt.for_body = NULL;
stmt->for_stmt.for_statement_list = NULL;
stmt->for_stmt.for_scope = new_scope(parser); // For the loop variables
raviX_next(ls); /* skip 'for' */
varname = check_name_and_next(ls); /* first variable name */
stmt->for_stmt.for_scope = new_scope(parser); // For the loop variables
raviX_next(ls); /* skip 'for' */
varname = check_name_and_next(ls); /* first variable name */
switch (ls->t.token) {
case '=':
stmt->type = STMT_FOR_NUM;
Expand All @@ -1261,7 +1280,8 @@ static struct ast_node *parse_if_cond_then_block(struct parser_state *parser)
struct lexer_state *ls = parser->ls;
/* test_then_block -> [IF | ELSEIF] cond THEN block */
raviX_next(ls); /* skip IF or ELSEIF */
struct ast_node *test_then_block = allocate_ast_node(parser, STMT_TEST_THEN); // This is not an AST node on its own
struct ast_node *test_then_block =
allocate_ast_node(parser, STMT_TEST_THEN); // This is not an AST node on its own
test_then_block->test_then_block.condition = parse_expression(parser); /* read condition */
test_then_block->test_then_block.test_then_scope = NULL;
test_then_block->test_then_block.test_then_statement_list = NULL;
Expand Down Expand Up @@ -1330,11 +1350,11 @@ static struct ast_node *parse_local_function_statement(struct parser_state *pars
static void limit_function_call_results(struct parser_state *parser, int num_lhs, struct ast_node_list *expr_list)
{
// FIXME probably doesn't handle var arg case
struct ast_node *last_expr = (struct ast_node *) ptrlist_last((struct ptr_list *) expr_list);
struct ast_node *last_expr = (struct ast_node *)ptrlist_last((struct ptr_list *)expr_list);
struct ast_node *call_expr = has_function_call(last_expr);
if (!call_expr)
return;
int num_expr = ptrlist_size((const struct ptr_list *) expr_list);
int num_expr = ptrlist_size((const struct ptr_list *)expr_list);
if (num_expr < num_lhs) {
call_expr->function_call_expr.num_results = (num_lhs - num_expr) + 1;
}
Expand Down Expand Up @@ -1493,8 +1513,8 @@ static struct ast_node *parse_statement(struct parser_state *parser)
stmt = parse_function_statement(parser, line);
break;
}
case TOK_local: { /* stat -> localstat */
raviX_next(ls); /* skip LOCAL */
case TOK_local: { /* stat -> localstat */
raviX_next(ls); /* skip LOCAL */
if (testnext(ls, TOK_function)) /* local function? */
stmt = parse_local_function_statement(parser);
else
Expand All @@ -1511,7 +1531,7 @@ static struct ast_node *parse_statement(struct parser_state *parser)
stmt = parse_return_statement(parser);
break;
}
case TOK_break: /* stat -> breakstat */
case TOK_break: /* stat -> breakstat */
case TOK_goto: { /* stat -> 'goto' NAME */
stmt = parse_goto_statment(parser);
break;
Expand Down Expand Up @@ -1722,4 +1742,3 @@ void raviX_destroy_compiler(struct compiler_state *container)
}
free(container);
}

5 changes: 4 additions & 1 deletion tests/input/t05_upvals.in
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ local function z(p1,p2)
b = 2
return x * y end
end
end
end
#
local _ENV = {}; return function() x = 1 end
#
1 change: 1 addition & 0 deletions tests/runtparse.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,5 @@ $command "function foo(bar: closure, zee: My.User.Type) end"
$command "return (f())"
$command "return {g()}, f(g())"

$command "local _ENV = {}; return function() x = 1 end"
exit 0

0 comments on commit 0f4f01a

Please sign in to comment.