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 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 cmd = exec::cmd(fname, arglist...)?; let proc = exec::start(&cmd)?; let status = exec::wait(&proc)?; }; 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]))?))?; };