Skip to content

Commit

Permalink
compiler: Add more work toward properly cataloging all funcs
Browse files Browse the repository at this point in the history
DCO-1.1-Signed-off-by: Ellie <[email protected]>
  • Loading branch information
ell1e committed Nov 23, 2023
1 parent 469c76f commit 7fbf784
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 9 deletions.
123 changes: 118 additions & 5 deletions src/compiler/ast/analyze/analyze.h64
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,93 @@ func stmt_list_contains_later_call(
return no
}

func _basic_check_and_analyze_do(
func advanced_phase2_later_and_computevals(
stmts, msgs=none, project_file=none
) {
func check_and_analyze_recurse(
stmts, msgs
) {
for stmt in stmts {
if stmt.kind == cast.N_STMT_FUNC {
var is_later_func = no
for block in stmt.subblocks {
if stmt_list_contains_later_call(
block, check_recursive=yes,
include_later_ignore=no,
recurse_into_funcs=no) {
is_later_func = yes
break
}
}
stmt.func_scope.is_later_func = is_later_func
}

# FIXME: go through all sorts of things we could already
# know the value of at compile-time, and try to iteratively
# find out as many values already as we can.

# Blocks:
if stmt.kind == cast.N_STMT_IF or
stmt.kind == cast.N_STMT_DO {
for clause in stmt.subexprs {
for block in clause.subblocks {
if not check_and_analyze_recurse(block, msgs) {
return no
}
}
}
} elseif stmt.subblocks.len > 0 {
for block in stmt.subblocks {
if not check_and_analyze_recurse(block, msgs) {
return no
}
}
}
}
return yes
}
return check_and_analyze_recurse(
stmts, msgs
)
}

func advanced_phase1_globalrefs(
stmts, msgs=none, project_file=none
) {
func check_and_analyze_recurse(
stmts, msgs) {
for stmt in stmts {
# FIXME
# IMPORTANT: we also want to auto-const all vrs here already.
# (Then the next state, the iteration stage, can do better
# guesses, especially inside functions.)

# Blocks:
if stmt.kind == cast.N_STMT_IF or
stmt.kind == cast.N_STMT_DO {
for clause in stmt.subexprs {
for block in clause.subblocks {
if not check_and_analyze_recurse(block, msgs) {
return no
}
}
}
} elseif stmt.subblocks.len > 0 {
for block in stmt.subblocks {
if not check_and_analyze_recurse(block, msgs) {
return no
}
}
}
}
return yes
}
return check_and_analyze_recurse(
stmts, msgs
)
}

func basic_phase_nestingdepth_and_misc(
stmts, msgs=none, project_file=none
) {
func check_and_analyze_recurse(
Expand All @@ -93,9 +179,6 @@ func _basic_check_and_analyze_do(
return no
}
for stmt in stmts {
# Expressions (FIXME):

# Blocks:
if stmt.kind == cast.N_STMT_IF or
stmt.kind == cast.N_STMT_DO {
for clause in stmt.subexprs {
Expand All @@ -122,11 +205,41 @@ func _basic_check_and_analyze_do(
)
}

func do_advanced_check_and_analysis(project, msgs) {
func process_file(pfile) {
pfile.ensure_ast() later:

if not advanced_phase1_globalrefs(
pfile.ast.stmts, msgs,
project_file=pfile) {
return later no
}
if not advanced_phase2_later_and_computevals(
pfile.ast.stmts, msgs,
project_file=pfile) {
return later no
}
return later yes
}
var check_went_ok = project.do_for_all_files(process_file)
later:

await check_went_ok
for m in msgs {
if m.kind == msg.M_ERROR {
check_went_ok = no
}
}

return later check_went_ok
}

func do_basic_check_and_analysis(project, msgs) {
func process_file(pfile) {
pfile.ensure_ast() later:

if not _basic_check_and_analyze_do(pfile.ast.stmts, msgs,
if not basic_phase_nestingdepth_and_misc(
pfile.ast.stmts, msgs,
project_file=pfile) {
return later no
}
Expand Down
13 changes: 11 additions & 2 deletions src/compiler/ast/transform/transform.h64
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
# license, see accompanied LICENSE.md.

import compiler.ast as ast
import compiler.ast.analyze as ast_analyze
import compiler.ast.transform.later_transform as later_transform

type VisitQueueEntry {
Expand Down Expand Up @@ -154,9 +155,17 @@ func visit_ast_tree(node, visit_cb, pass_func_boundaries=yes) {
}

func do_all_transformations(project, msgs, optimize=yes) {
later_transform.first_pass_later_transform(project, msgs)
var success = ast_analyze.do_advanced_check_and_analysis(
project, msgs) later:

await success
if not success {
return later none
}
success = later_transform.first_pass_later_transform(project, msgs)
later:

return later none
await success
return later success
}

1 change: 1 addition & 0 deletions src/compiler/project.h64
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import text from core.horse64.org
import uri from core.horse64.org

import compiler.ast as ast
import compiler.ast.func_stmt as func_stmt
import compiler.ast.import_stmt as import_stmt
import compiler.ast.transform as transform
import compiler.cext as cext
Expand Down
15 changes: 13 additions & 2 deletions src/compiler/storage/scope/global_scope.h64
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import compiler.ast as ast
import compiler.ast.enum_stmt as enum_stmt
import compiler.ast.func_stmt as func_stmt
import compiler.ast.type_stmt as type_stmt
import compiler.msg as msg
import compiler.storage.scope as storage_scope
Expand Down Expand Up @@ -76,6 +77,10 @@ func GlobalScope.ensure_assigned_storage(msgs=none,
return
}
var storage_num = 1
if project_file != none and project_file.project != none {
storage_num = project_file.project.
last_global_storage_id + 1
}
for name in self.name_to_stmt_map {
var value = self.name_to_stmt_map[name]
if typename(value) == "list" {
Expand All @@ -98,6 +103,10 @@ func GlobalScope.ensure_assigned_storage(msgs=none,
storage_num += 1
}
}
if project_file != none and project_file.project != none {
project_file.project.last_global_storage_id =
storage_num - 1
}
# Now register enum values in the global scope too:
var names_unchanged = self.name_to_stmt_map.keys()
for name in names_unchanged {
Expand Down Expand Up @@ -216,7 +225,7 @@ func has_global_scope_duplicate(
return no
}

func get_statement_global_name(statement) {
func get_statement_global_names(statement) {
if statement.kind == ast.N_STMT_IMPORT {
if statement.renamed_as != none {
return [statement.renamed_as]
Expand All @@ -242,7 +251,7 @@ func process_toplevel_stmt(
scope, statement, msgs,
project_file=none, debug=no) {
assert(statement != none)
var names = get_statement_global_name(statement)
var names = get_statement_global_names(statement)
if names.len == 0 {
return
}
Expand Down Expand Up @@ -270,6 +279,8 @@ func process_toplevel_stmt(
stand_in_node = new type_stmt.TypeStmt()
} elseif statement.kind == ast.N_STMT_TYPEEXTEND {
stand_in_node = new type_stmt.TypeExtendStmt()
} elseif statement.kind == ast.N_STMT_FUNC {
stand_in_node = new func_stmt.FuncStmt()
} else {
stand_in_node = new ast.StmtNode()
}
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/storage/scope/scope.h64
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import compiler.ast as ast
import compiler.ast.enum_stmt as enum_stmt
import compiler.ast.func_stmt as func_stmt
import compiler.ast.transform as transform
import compiler.ast.type_stmt as type_stmt
import compiler.msg as msg
Expand All @@ -46,9 +47,16 @@ func SymbolInfo.init(name) {
type FuncScope {
var last_storage_id = 0
var is_type_attr = no
var is_later_func = no
var global_storage_id = 0
var owning_type_storage_id
var parent
}

extend func_stmt.FuncStmt {
var func_scope
}

type TypeScope {
const is_enum = no
var node_map = {->}
Expand Down Expand Up @@ -105,5 +113,7 @@ extend enum_stmt.EnumExtendStmt {

extend project.Project {
var type_or_enum_scope_map = {->}

var storage_id_to_global_scope_map = {->}
}

64 changes: 64 additions & 0 deletions src/compiler/storage/storage.h64
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,30 @@

import compiler.ast as ast
import compiler.ast.expr as ast_expr
import compiler.ast.func_stmt as func_stmt
import compiler.ast.transform as transform
import compiler.cext as cext
import compiler.project as project
import compiler.storage.scope as scope
import compiler.storage.scope.global_scope as global_scope
import compiler.storage.ref as storage_ref

extend project.Project {
var did_compute_scopes = no

var last_global_storage_id = 0
}

extend ast_expr.IdRefExpr {
var ref
}

func project.Project.get_free_global_storage_slot {
var v = self.last_global_storage_id + 1
self.last_global_storage_id = v
return v
}

func project.Project.compute_all_scopes(msgs, debug=no) {
if self.did_compute_scopes {
if debug {
Expand Down Expand Up @@ -309,6 +319,7 @@ func project.Project.compute_all_scopes(msgs, debug=no) {
}
if node.kind == ast.N_STMT_FUNC {
inner_scope.func_scope = new scope.FuncScope()
node.func_scope = inner_scope.func_scope
if inner_scope.parent != none {
inner_scope.func_scope.parent =
inner_scope.parent.func_scope
Expand Down Expand Up @@ -398,6 +409,52 @@ func project.Project.compute_all_scopes(msgs, debug=no) {
pfile.global_scope.ensure_assigned_storage(
msgs=msgs, project_file=pfile)
func expr_idref_resolve_visitor(node, parent) {
if node.kind == ast.N_STMT_FUNC and
node.func_scope != none {
var is_global = no
var storage_id = 0
if (parent == none or not has_attr(parent, "kind")) and
node.type_path == none {
# Global function. Get it from global scope:
is_global = yes
if pfile.global_scope.
name_to_stmt_map.has(node.label) {
var el = pfile.global_scope.
name_to_stmt_map[node.label]
if typename(el) != "list" and
el.kind == ast.N_STMT_FUNC and
el.symbol_info.storage_id != none {
storage_id = el.symbol_info.storage_id
}
}
if storage_id > 0 {
# Will only not get here as a run-on error
# in damaged code.
node.func_scope.global_storage_id = storage_id
}
} else {
assert(node.func_scope.global_storage_id == 0 or
node.func_scope.global_storage_id == none)
storage_id = self.get_free_global_storage_slot()
assert(storage_id != 0 and storage_id != none)
node.func_scope.global_storage_id = storage_id
}
if storage_id > 0 and not is_global {
# Register this without a name, we need all funcs in
# their global scope.
var stand_in_node = new func_stmt.FuncStmt()
pfile.global_scope.storage_id_to_entry[
storage_id] = stand_in_node
stand_in_node.line = node.line
stand_in_node.col = node.col
}
if storage_id > 0 and
pfile.global_scope.storage_id_to_entry.
has(storage_id) {
pfile.global_scope.storage_id_to_entry[storage_id].
func_scope = node.func_scope
}
}
if node.kind == ast.N_EXPR_IDREF {
if parent.kind == ast.N_EXPR_BINOP and
parent.optoken.str == "." {
Expand Down Expand Up @@ -474,6 +531,13 @@ func project.Project.compute_all_scopes(msgs, debug=no) {
pfile.ast, expr_idref_resolve_visitor) later:

await success
for storage_id in pfile.global_scope.
storage_id_to_entry.keys() {
assert(not self.storage_id_to_global_scope_map.
has(storage_id))
self.storage_id_to_global_scope_map[storage_id] =
pfile.global_scope
}
assert(success == yes)
return later success
}
Expand Down

0 comments on commit 7fbf784

Please sign in to comment.