// module_load.cm — Module loading simulation (macro benchmark)
// Simulates parsing many small modules, linking, and running.
// Tests the "build scenario" pattern.

var json = use('json')

// Simulate a small module: parse token stream + build AST + evaluate
function tokenize(src) {
  var tokens = []
  var i = 0
  var ch = null
  var chars = array(src)
  var buf = ""

  for (i = 0; i < length(chars); i++) {
    ch = chars[i]
    if (ch == " " || ch == "\n" || ch == "\t") {
      if (length(buf) > 0) {
        push(tokens, buf)
        buf = ""
      }
    } else if (ch == "(" || ch == ")" || ch == "+" || ch == "-"
            || ch == "*" || ch == "=" || ch == ";" || ch == ",") {
      if (length(buf) > 0) {
        push(tokens, buf)
        buf = ""
      }
      push(tokens, ch)
    } else {
      buf = buf + ch
    }
  }
  if (length(buf) > 0) push(tokens, buf)
  return tokens
}

// Build a simple AST from tokens
function parse_tokens(tokens) {
  var ast = []
  var i = 0
  var tok = null
  var node = null
  for (i = 0; i < length(tokens); i++) {
    tok = tokens[i]
    if (tok == "var" || tok == "def") {
      node = {type: "decl", kind: tok, name: null, value: null}
      i++
      if (i < length(tokens)) node.name = tokens[i]
      i++ // skip =
      i++
      if (i < length(tokens)) node.value = tokens[i]
      push(ast, node)
    } else if (tok == "return") {
      node = {type: "return", value: null}
      i++
      if (i < length(tokens)) node.value = tokens[i]
      push(ast, node)
    } else if (tok == "function") {
      node = {type: "func", name: null, body: []}
      i++
      if (i < length(tokens)) node.name = tokens[i]
      // Skip to matching )
      while (i < length(tokens) && tokens[i] != ")") i++
      push(ast, node)
    } else {
      push(ast, {type: "expr", value: tok})
    }
  }
  return ast
}

// Evaluate: simple symbol table + resolution
function evaluate(ast, env) {
  var result = null
  var i = 0
  var node = null
  for (i = 0; i < length(ast); i++) {
    node = ast[i]
    if (node.type == "decl") {
      env[node.name] = node.value
    } else if (node.type == "return") {
      result = node.value
      if (env[result]) result = env[result]
    } else if (node.type == "func") {
      env[node.name] = node
    }
  }
  return result
}

// Generate fake module source code
function generate_module(id, dep_count) {
  var src = ""
  var i = 0
  src = src + "var _id = " + text(id) + ";\n"
  for (i = 0; i < dep_count; i++) {
    src = src + "var dep" + text(i) + " = use(mod_" + text(i) + ");\n"
  }
  src = src + "var x = " + text(id * 17) + ";\n"
  src = src + "var y = " + text(id * 31) + ";\n"
  src = src + "function compute(a, b) { return a + b; }\n"
  src = src + "var result = compute(x, y);\n"
  src = src + "return result;\n"
  return src
}

// Simulate loading N modules with dependency chains
function simulate_build(n_modules, deps_per_module) {
  var modules = []
  var loaded = {}
  var i = 0
  var j = 0
  var src = null
  var tokens = null
  var ast = null
  var env = null
  var result = null
  var total_tokens = 0
  var total_nodes = 0

  // Generate all module sources
  for (i = 0; i < n_modules; i++) {
    src = generate_module(i, deps_per_module)
    push(modules, src)
  }

  // "Load" each module: tokenize → parse → evaluate
  for (i = 0; i < n_modules; i++) {
    tokens = tokenize(modules[i])
    total_tokens += length(tokens)

    ast = parse_tokens(tokens)
    total_nodes += length(ast)

    env = {}
    // Resolve dependencies
    for (j = 0; j < deps_per_module; j++) {
      if (j < i) {
        env["dep" + text(j)] = loaded["mod_" + text(j)]
      }
    }

    result = evaluate(ast, env)
    loaded["mod_" + text(i)] = result
  }

  return {
    modules: n_modules,
    total_tokens: total_tokens,
    total_nodes: total_nodes,
    last_result: result
  }
}

// Dependency graph analysis (topological sort simulation)
function topo_sort(n_modules, deps_per_module) {
  // Build adjacency list
  var adj = {}
  var in_degree = {}
  var i = 0
  var j = 0
  var name = null
  var dep = null

  for (i = 0; i < n_modules; i++) {
    name = "mod_" + text(i)
    adj[name] = []
    in_degree[name] = 0
  }

  for (i = 0; i < n_modules; i++) {
    name = "mod_" + text(i)
    for (j = 0; j < deps_per_module; j++) {
      if (j < i) {
        dep = "mod_" + text(j)
        push(adj[dep], name)
        in_degree[name] = in_degree[name] + 1
      }
    }
  }

  // Kahn's algorithm
  var queue = []
  var keys = array(in_degree)
  for (i = 0; i < length(keys); i++) {
    if (in_degree[keys[i]] == 0) push(queue, keys[i])
  }

  var order = []
  var current = null
  var neighbors = null
  var qi = 0
  while (qi < length(queue)) {
    current = queue[qi]
    qi++
    push(order, current)
    neighbors = adj[current]
    if (neighbors) {
      for (i = 0; i < length(neighbors); i++) {
        in_degree[neighbors[i]] = in_degree[neighbors[i]] - 1
        if (in_degree[neighbors[i]] == 0) push(queue, neighbors[i])
      }
    }
  }

  return order
}

return {
  // Small build: 50 modules, 3 deps each
  build_50: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = simulate_build(50, 3)
    }
    return result
  },

  // Medium build: 200 modules, 5 deps each
  build_200: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = simulate_build(200, 5)
    }
    return result
  },

  // Large build: 500 modules, 5 deps each
  build_500: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = simulate_build(500, 5)
    }
    return result
  },

  // Topo sort of 500 module dependency graph
  topo_sort_500: function(n) {
    var i = 0
    var order = null
    for (i = 0; i < n; i++) {
      order = topo_sort(500, 5)
    }
    return order
  }
}
