use fmt; use internal::parser; use strconv; use strings; use os::exec; export type variable = (str, str); export type interpreter = struct { vars: []variable, }; export type error = !(interperror | exec::error | nomem); export type interperror = !str; export fn interpret(it: *interpreter, tree: parser::ast) void = { match (tree.value) { case parser::assign => assign(it, tree.children)!; case parser::finvoke => match (invoke(it, tree.children)) { case let e: exec::error => fmt::errorln(exec::strerror(e))!; case void => void; case let e: interperror => fmt::fatal(e); case nomem => fmt::fatal("No memory left"); }; }; }; fn printinvoke(it: *interpreter, nodes: []parser::ast) (void | error) = { const fname = nodes[0].value as parser::varname; const arglist = nodes[1].value as parser::arglist; let args = strings::join(", ", arglist...)!; defer free(args); fmt::errorfln("{}: {}", fname, args)!; }; fn print(args: str...) void = { for (let arg .. args) { fmt::println(arg)!; }; }; fn invoke(it: *interpreter, nodes: []parser::ast) (void | error) = { const fname = nodes[0].value as parser::varname; const arglist = nodes[1].value as parser::arglist; let sarglist: []str = []; defer strings::freeall(sarglist); for (let arg .. arglist) { append(sarglist, replacevars(it, arg))!; }; switch (fname) { case "print" => print(sarglist...); case => let cmd = exec::cmd(fname, sarglist...)?; let proc = exec::start(&cmd)?; let status = exec::wait(&proc)?; }; }; fn replacevars(it: *interpreter, s: str) str = { let repls: [](str, str) = []; defer for (let repl .. repls) { free(repl.0); }; for (let var .. it.vars) { let v = fmt::asprintf("${{{}}}", var.0)!; append(repls, (v, var.1))!; }; let sa = strings::multireplace(s, repls...)!; return sa; }; fn assign(it: *interpreter, nodes: []parser::ast) (void | error) = { const varname = nodes[0].value as parser::varname; const operation = nodes[1].value as parser::operation; let value = 0; let stack: []int = []; for (let i = 0z; i < len(operation.stack); i += 1) { const arg = operation.stack[i]; match (arg) { case let i: int => append(stack, i)?; case let o: parser::operator => if (len(stack) >= 2) { let last = len(stack) - 1; let val = switch (o) { case parser::operator::ADD => yield stack[last] + stack[last-1]; case parser::operator::SUBTRACT => yield stack[last] - stack[last-1]; case parser::operator::MULTIPLY => yield stack[last] * stack[last-1]; case parser::operator::DIVIDE => yield stack[last] / stack[last-1]; }; delete(stack[last-1..]); append(stack, val)?; } else { return "Invalid operation": interperror; }; }; }; let last = len(stack) - 1; append(it.vars, (varname, strings::dup(strconv::itos(stack[last]))?))?; };