bash function scope

by Richard Hunter

JavaScript

const stack = []
const fnDefs = {}
const blockStack = []
const FUNC = "fn"

let functionUnderDefinition = []
let definingFn = false

class Scope {
  constructor() {
    this.variables = {}
  }

  getLocal() {}

  setLocal(name, value) {
    this.variables[name] = value
  }
}

function callFunction(name) {
  const fn = fnDefs[name]
  const scope = new Scope()
  stack.push(scope)
  fn.run()
}

class Fn {
  constructor(name, lines) {
    this.name = name
    this.lines = lines
  }
  run() {
    this.lines.forEach(processLine);
  }
}

const lines = ["blah", "foo () {", "local a='this is a'", "b", "}", "c", "foo"]

function matchOpenFn(token) {
  return token.match(/\w+\s*\(\)\s*{$/)
}

function matchCloseFn(token) {
  return token.match(/}/)
}

function matchLocalVariable(token) {
  return token.match(/local\s*(\w+)='([\w\s]*)'/)
}

const rootScope = new Scope()
stack.push(rootScope)

function processLine(line) {
 // not realistic, as we're assuming each line only has one token
  if (matchOpenFn(line)) {
    blockStack.push({
      name: "foo",
      type: FUNC,
    })
    definingFn = true
  } else if (matchCloseFn(line)) {
    const block = blockStack[0]
    if (block?.type === FUNC) {
      blockStack.pop()
      const fn = new Fn(block.name, [...functionUnderDefinition])
      fnDefs[block.name] = fn
      functionUnderDefinition = []
      definingFn = false
    } else {
      throw new Error("syntax error")
    }
  } else if (fnDefs[line]) {
    callFunction(line)
  } else if (definingFn) {
    functionUnderDefinition.push(line)
  } else if (matchLocalVariable(line)) {
  	const result = matchLocalVariable(line);
    const name = result[1];
    const value = result[2];
    
    stack[0].setLocal(name, value);
  	console.log(stack)
  } else {
    console.log("do something else")
  }
}

lines.forEach(processLine);