

Aug 25 20:15 2013 repl.lua Page 1


--[[ REPL Module 
     Read-Evaluate-Print Loop command line interface
     KILT -- Kamin Interpreters in Lua Toolset
     H. Conrad Cunningham, Professor
     Computer and Information Science
     University of Mississippi

Developed for CSci 658, Software Language Engineering, Fall 2013

2012-08-17: Separated into a module derived from Core, etc.
2012-08-21: Added explicit dependency setters
2012-08-22: Added require of new Utilities module
2012-08-24: Cleaned dependencies and comments

1234567890123456789012345678901234567890123456789012345678901234567890

This module implements a simple, text-based, interactive user
interface to the interpreter, commonly called a REPL.  It repeatedly
prompts for an expression, READs and parses the user's input
expression, EVALUATEs it, and then PRINTs the result.  It calls the
Parser and Evaluator.

Before processing, the REPL removes any leadings spaces and
end-of-line comment from each line.  A comment is any text beginning 
with a semicolon ";" and continuing until the end of the line.

If it detects unbalanced parentheses on a line, it prompts the user
for the continuation of that line until the parentheses balance.

The REPL continues to read expressions until the user enters the
command "quit".

--]]

-- KILT tree utilities library
local util = require "utilities"
local treeConcat, printTree = util.treeConcat, util.printTree

-- REPL MODULE DEPENDENDENCY WIRING

-- globalEnv table
local globalEnv
local function setGlobalEnv(e) globalEnv = e end

-- parse(string) function
local parse
local function setParse(p) parse = p end

-- trimSpaces(string) function
local trimSpaces
local function setTrimSpaces(ts) trimSpaces = ts end

-- trimComment(string) function







Aug 25 20:15 2013 repl.lua Page 2


local trimComment
local function setTrimComment(tc) trimComment = tc end

-- getCommand(string) function
local getCommand
local function setGetCommand(gc) getCommand = gc end

-- evalScript function 
local evalScript
local function setEvalScript(es) evalScript = es end

-- valToString(value)
local valToString
local function setValToString(vts) valToString = vts end

-- REPL prompts, with defaults
local mainPrompt, contPrompt  = "> ", ">>"
local function setPrompts(mp,cp)
  mainPrompt, contPrompt = mp, cp
end

-- REPL functions

-- The function "readExpression" interactively reads an expression
-- entered at the command line.

local function readExpr()
  local line, ch 
  local input     = {}
  local bal       = 0  -- #left parentheses - #right parentheses
  local fullinput = false

  -- loop until a complete expression is entered
  while not fullinput do
    if bal == 0 then 
      io.write(mainPrompt)
    elseif bal > 0 then
      io.write(contPrompt)
    end  -- bal < 0 means a syntax error, caught below
    line = io.read("*l")

    -- trim leading spaces and end-of-line comment
    line = trimSpaces(line)
    line = trimComment(line)

    -- check for balanced parentheses, need for additional input
    for i = 1, #line do
      ch = string.sub(line,i,i)
      if ch == "(" then 
        bal = bal + 1
      elseif ch == ")" then 
        bal = bal - 1
      end







Aug 25 20:15 2013 repl.lua Page 3


      if bal < 0 then -- found ) before matching (
        break
      end
    end
    input[#input+1] = line

    if bal < 0 then -- too many )'s, syntax error, restart input
      print("Syntax error. Input ignored: "..table.concat(input,"\n"))
      input, bal = {}, 0
    elseif line ~= "" and bal == 0 then -- complete input expression
      fullinput = true
    end -- bal > 0, continue gathering input lines
  end
  return table.concat(input,"\n")
end


-- Procedure "readEvalPrint" drives the Read-Evaluate-Print-Loop
-- command line interface.  It repeatedly reads an expression, parses
-- it, evaluates it, and prints the resulting value until the command
-- "quit" is entered.

local function readEvalPrint()
  local wired = globalEnv and parse and trimSpaces and trimComment 
                and getCommand and evalScript and valToString
  if not wired then
    error("Dependencies for module REPL are not set.")
  end
  local input, script, result
  local quitting = false
  while not quitting do 
    input = readExpr()                          -- READ (then parse)
    local cmd = getCommand(input)
    quitting = (cmd == "quit")
    if not quitting then
      script = nil
      local parseok, parsemsg = pcall(function()
        script = parse(input)
        print("DEBUG: after parse in repl -> "..treeConcat(script))
      end)
      if parseok then
        local evalok, evalmsg = pcall(function()
          result = evalScript(script,globalEnv) -- EVALUATE
          print("DEBUG: after evalScript in repl -> " ..
                treeConcat(result))
        end)
        if evalok then 
          local output = valToString(result[1])
          print(output)                         -- PRINT
        else
          print(evalmsg)
          print("Evaluation failed for " .. input)
          print("Input ignored.")







Aug 25 20:15 2013 repl.lua Page 4


        end
      else
        print(parmsg)
        print("Parsing failed for " .. input)
        print("Input ignored.")
      end
    end
    input = ""
  end
end


-- MODULE EXPORT LIST

return { 
  readEvalPrint  = readEvalPrint,  -- main function
  setGlobalEnv   = setGlobalEnv,   -- dependency setters
  setParse       = setParse,
  setTrimSpaces  = setTrimSpaces,
  setTrimComment = setTrimComment,
  setGetCommand  = setGetCommand,
  setEvalScript  = setEvalScript,
  setValToString = setValToString,
  setPrompts     = setPrompts      -- prompt parameter setter
}

































