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);