1
0
Fork 0
mirror of https://github.com/notwa/mm synced 2024-11-05 06:49:03 -08:00
mm/Lua/lib/lips/Muncher.lua
2016-04-02 08:42:22 -07:00

161 lines
3.5 KiB
Lua

local format = string.format
local insert = table.insert
local data = require "lips.data"
local util = require "lips.util"
local Token = require "lips.Token"
local arg_types = {
NUM = true,
REG = true,
DEFSYM = true,
LABELSYM = true,
RELLABELSYM = true,
}
local Muncher = util.Class()
-- no base init method
function Muncher:error(msg)
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
end
function Muncher:token(t, val)
-- note: call Token directly if you want to specify fn and line manually
if type(t) == 'table' then
t.fn = self.fn
t.line = self.line
return Token(t)
else
return Token(self.fn, self.line, t, val)
end
end
function Muncher:advance()
self.i = self.i + 1
self.t = self.tokens[self.i]
self.tt = self.t.tt
self.tok = self.t.tok
self.fn = self.t.fn
self.line = self.t.line
return self.t
end
function Muncher:is_EOL()
return self.tt == 'EOL' or self.tt == 'EOF'
end
function Muncher:expect_EOL()
if self:is_EOL() then
self:advance()
return
end
self:error('expected end of line')
end
function Muncher:optional_comma()
if self.tt == 'SEP' and self.tok == ',' then
self:advance()
return true
end
end
function Muncher:number()
if self.tt ~= 'NUM' then
self:error('expected number')
end
local t = self.t
self:advance()
return self:token(t)
end
function Muncher:string()
if self.tt ~= 'STRING' then
self:error('expected string')
end
local t = self.t
self:advance()
return self:token(t)
end
function Muncher:register(registers)
registers = registers or data.registers
if self.tt ~= 'REG' then
self:error('expected register')
end
local t = self.t
if not registers[t.tok] then
self:error('wrong type of register')
end
self:advance()
return self:token(t)
end
function Muncher:deref()
if self.tt ~= 'OPEN' then
self:error('expected opening parenthesis for dereferencing')
end
self:advance()
if self.tt ~= 'REG' then
self:error('expected register to dereference')
end
local t = self.t
self:advance()
if self.tt ~= 'CLOSE' then
self:error('expected closing parenthesis for dereferencing')
end
self:advance()
return self:token(t)
end
function Muncher:const(relative, no_label)
if self.tt ~= 'NUM' and self.tt ~= 'LABELSYM' then
self:error('expected constant')
end
if no_label and self.tt == 'LABELSYM' then
self:error('labels are not allowed here')
end
local t = self:token(self.t)
if relative then
if self.tt == 'LABELSYM' then
t.tt = 'LABELREL'
else
t.tt = 'REL'
end
end
self:advance()
return t
end
function Muncher:special()
if self.tt ~= 'SPECIAL' then
self:error('expected special name to call')
end
local name = self.tok
self:advance()
if self.tt ~= 'OPEN' then
self:error('expected opening parenthesis for special call')
end
local args = {}
while true do
local arg = self:advance()
if not arg_types[arg.tt] then
self:error('invalid argument type')
else
self:advance()
end
if self.tt == 'SEP' then
insert(args, arg)
elseif self.tt == 'CLOSE' then
insert(args, arg)
break
else
self:error('unexpected token in argument list')
end
end
return name, args
end
return Muncher