better compiler warnings adn errors

This commit is contained in:
2026-02-20 12:40:49 -06:00
parent 54e5be0773
commit 8d449e6fc6
10 changed files with 679 additions and 93 deletions

View File

@@ -182,9 +182,99 @@ function analyze(src, filename) {
// Lazy-loaded verify_ir module (loaded on first use)
var _verify_ir_mod = null
// Module summary extraction for cross-program analysis.
// Scans mcode IR for use() call patterns and attaches summaries.
// _summary_resolver is set after shop loads (null during bootstrap).
var _summary_resolver = null
function extract_module_summaries(compiled) {
if (_summary_resolver == null) return null
var instrs = null
var summaries = []
var i = 0
var j = 0
var n = 0
var instr = null
var prev = null
var op = null
var use_slots = {}
var frame_map = {}
var arg_map = {}
var val_slot = 0
var f_slot = 0
var path = null
var result_slot = 0
var summary = null
if (compiled.main == null) return null
instrs = compiled.main.instructions
if (instrs == null) return null
n = length(instrs)
// Pass 1: find access(slot, {make:"intrinsic", name:"use"})
i = 0
while (i < n) {
instr = instrs[i]
if (is_array(instr) && instr[0] == "access") {
if (is_object(instr[2]) && instr[2].make == "intrinsic" && instr[2].name == "use") {
use_slots[text(instr[1])] = true
}
}
i = i + 1
}
// Pass 2: find frame(frame_slot, use_slot), setarg with string, invoke
i = 0
while (i < n) {
instr = instrs[i]
if (is_array(instr)) {
op = instr[0]
if (op == "frame" || op == "goframe") {
if (use_slots[text(instr[2])] == true) {
frame_map[text(instr[1])] = true
}
} else if (op == "setarg") {
if (frame_map[text(instr[1])] == true) {
val_slot = instr[3]
j = i - 1
while (j >= 0) {
prev = instrs[j]
if (is_array(prev) && prev[0] == "access" && prev[1] == val_slot && is_text(prev[2])) {
arg_map[text(instr[1])] = prev[2]
break
}
j = j - 1
}
}
} else if (op == "invoke" || op == "tail_invoke") {
f_slot = instr[1]
path = arg_map[text(f_slot)]
if (path != null) {
result_slot = instr[2]
summary = _summary_resolver(path)
if (summary != null) {
summaries[] = {slot: result_slot, summary: summary}
}
}
}
}
i = i + 1
}
if (length(summaries) > 0) return summaries
return null
}
// Run AST through mcode pipeline -> register VM
function run_ast_fn(name, ast, env) {
var compiled = mcode_mod(ast)
var ms = null
var optimized = null
var _di = 0
var _diag = null
var _has_errors = false
var mcode_json = null
var mach_blob = null
if (os._verify_ir) {
if (_verify_ir_mod == null) {
_verify_ir_mod = load_pipeline_module('verify_ir', pipeline_env)
@@ -192,13 +282,31 @@ function run_ast_fn(name, ast, env) {
compiled._verify = true
compiled._verify_mod = _verify_ir_mod
}
var optimized = streamline_mod(compiled)
if (!_no_warn) {
compiled._warn = true
ms = extract_module_summaries(compiled)
if (ms != null) {
compiled._module_summaries = ms
}
}
optimized = streamline_mod(compiled)
if (optimized._verify) {
delete optimized._verify
delete optimized._verify_mod
}
var mcode_json = json.encode(optimized)
var mach_blob = mach_compile_mcode_bin(name, mcode_json)
if (optimized._diagnostics != null && length(optimized._diagnostics) > 0) {
_di = 0
_has_errors = false
while (_di < length(optimized._diagnostics)) {
_diag = optimized._diagnostics[_di]
print(`${_diag.file}:${text(_diag.line)}:${text(_diag.col)}: ${_diag.severity}: ${_diag.message}\n`)
if (_diag.severity == "error") _has_errors = true
_di = _di + 1
}
if (_has_errors) disrupt
}
mcode_json = json.encode(optimized)
mach_blob = mach_compile_mcode_bin(name, mcode_json)
return mach_load(mach_blob, env)
}
@@ -227,6 +335,9 @@ var _init = init
if (_init != null && _init.native_mode)
native_mode = true
// Inherit warn mode from init (set by C for --no-warn)
var _no_warn = (_init != null && _init.no_warn) ? true : false
// CLI path: convert args to init record
if (args != null && (_init == null || !_init.program)) {
_program = args[0]
@@ -424,6 +535,19 @@ core_extras.native_mode = native_mode
// NOW load shop -- it receives all of the above via env
var shop = use_core('internal/shop')
use_core('build')
// Wire up module summary resolver now that shop is available
_summary_resolver = function(path) {
var resolved = shop.resolve_use_path(path, null)
if (resolved == null) return null
var summary_fn = function() {
return shop.summary_file(resolved)
} disruption {
return null
}
return summary_fn()
}
var time = use_core('time')
var toml = use_core('toml')

View File

@@ -519,6 +519,7 @@ var _ast_cache = {}
var _analyze_cache = {}
var _compile_cache = {}
var _index_cache = {}
var _summary_cache = {}
var get_tokenize = function() {
if (!_tokenize_mod) _tokenize_mod = use_cache['core/tokenize'] || use_cache['tokenize']
@@ -547,6 +548,14 @@ var get_index = function() {
}
return _index_mod
}
var _analyze_mod = null
var get_analyze = function() {
if (!_analyze_mod) {
_analyze_mod = use_cache['core/analyze'] || use_cache['analyze']
if (!_analyze_mod) _analyze_mod = Shop.use('analyze', 'core')
}
return _analyze_mod
}
Shop.tokenize_file = function(path) {
var src = text(fd.slurp(path))
@@ -611,6 +620,16 @@ Shop.index_file = function(path) {
return idx
}
Shop.summary_file = function(path) {
var src = text(fd.slurp(path))
var key = content_hash(stone(blob(src)))
if (_summary_cache[key]) return _summary_cache[key]
var idx = Shop.index_file(path)
var summary = get_analyze().module_summary(idx)
_summary_cache[key] = summary
return summary
}
Shop.mcode_file = function(path) {
var folded = Shop.analyze_file(path)
return get_mcode()(folded)