Advertisement
Guest User

Magic interpreter in Lua

a guest
Apr 13th, 2013
330
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.97 KB | None | 0 0
  1. --okay, lets do this
  2. --keywords, so I dont forget any
  3. --unsummon, summon, summonhold, conjure, enchant, dispel, bind, bindself, with, empty, print, set, skip
  4.  
  5. --a spirit is something summoned and running, a spell is the scroll, or the recipe
  6. --spirits hold variables, spells don't
  7.  
  8. --THIS ONE WITH ONE INSTRUCTION PER TIME
  9.  
  10. function string:split(sep)
  11.         local sep, fields = sep or ":", {}
  12.         local pattern = string.format("([^%s]+)", sep)
  13.         self:gsub(pattern, function(c) fields[#fields+1] = c end)
  14.         return fields
  15. end
  16.  
  17. function parseline(s)
  18.     s = "("..s..")" --the fuck? is this lisp?
  19.     s = s:gsub("%("," ( "):gsub("%)"," ) "):gsub(" +"," ")
  20.     local t = s:split(" ")
  21.     return read_from(t)
  22. end
  23.  
  24.     function read_from(tokens)
  25.         if #tokens == 0 then
  26.             error ( "unexpected EOF while reading" )
  27.         end
  28.         local token = tokens[1]
  29.         table.remove(tokens,1)
  30.         if "(" == token then
  31.             local L = {}
  32.             while tokens[1] ~= ")" do
  33.                 table.insert(L, read_from(tokens))
  34.             end
  35.             table.remove(tokens,1)  --pop off ")"
  36.             return L
  37.         elseif ")" == token then
  38.             error("unexpected )")
  39.         else
  40.             return token
  41.         end
  42.     end
  43.  
  44. function parsefile(s)
  45.     s = s:gsub("\n+","\n")
  46.     return map(parseline,s:split("\n"))
  47. end
  48.  
  49. function map(func,t)
  50.     local t2 = {}
  51.     for x=1,#t do
  52.         t2[x] = func(t[x])
  53.     end
  54.     return t2
  55. end
  56.  
  57. function conjureempty()
  58.     return {spells={}}
  59. end
  60.  
  61. function enchant(form,t)    --of course a syntax check must be done first, right??
  62.     table.insert(form.spells,t)
  63. end
  64.  
  65. function setat(form,n,v)    --a form that isn't summoned is just a list
  66.     form.spells[n]=v
  67. end
  68.  
  69. function slice(t,start)
  70.     local t2 = {}
  71.     for x=start,#t do
  72.         table.insert(t2,t[x])
  73.     end
  74.     return t2
  75. end
  76.  
  77. function copy(t)
  78.     return slice(t,1)
  79. end
  80.  
  81. spiritlist = {}
  82. spiritcount = 0
  83.  
  84. function summon(form,bindings)
  85.     local spirit = {spells=copy(form.spells),bindings=bindings,p=1}  --must be a copy cuz it might be altered at runtime
  86.     spiritcount=spiritcount+1
  87.     spiritlist[spiritcount] = spirit
  88.     spirit.id = spiritcount
  89.     spirit.bindings.self = spirit   --not a special word, but a common var that can be changed with set! U WOOT!!
  90.     spirit.bindings.selfform = form
  91.     spirit.bindings.firstloop = true    --a useful boolean
  92.     return spirit
  93. end
  94.  
  95. function unsummon(spirit)   --need to remove it from the spirit list, and put a tag on it saying "dead"
  96.     spiritlist[spirit.id] = nil
  97.     spirit.dead=true
  98.     if spirit.bindings.summoner then
  99.         spirit.bindings.summoner.halt=false --this unhalts the summoner
  100.     end
  101. end
  102.  
  103. --function summonhold(form,bindings)
  104. --  local spirit = summon(form,bindings)
  105. --  while not spirit.dead do
  106. --      evalspirit(spirit)
  107. --  end
  108. --  return spirit
  109. --end
  110.  
  111. mymath2 = {["+"]=function (a,b) return a+b end,
  112.       ["-"]=function (a,b) return a-b end,
  113.       ["*"]=function (a,b) return a*b end,
  114.       ["/"]=function (a,b) return a/b end,
  115.       ["%"]=function (a,b) return a%b end,
  116.       ["="]=function (a,b) return a==b end,
  117.       ["!="]=function (a,b) return a~=b end,
  118.       [">"]=function (a,b) return a>b end,
  119.       ["<"]=function (a,b) return a<b end,
  120.       [">="]=function (a,b) return a>=b end,
  121.       ["<="]=function (a,b) return a<=b end,
  122.       ["and"]=function (a,b) return a and b end,    --yea, and as a function it's no good, I kno
  123.       ["concat"]=function (a,b) return tostring(a)..tostring(b) end}
  124.  
  125. mymath1 = {["not"] = function (a) return (not a) end,
  126.        ["sin"] = function (a) return math.sin(a) end,
  127.        ["cos"] = function (a) return math.cos(a) end,
  128.        ["tan"] = function (a) return math.tan(a) end}
  129.        
  130.  
  131. function processwith(t,spirit)
  132.     local bindings = {}
  133.     local count = 1
  134.     while true do
  135.         bindings[t[count]] = evalline(t[count+1],spirit)
  136.         --print(t[count],bindings[t[count]])
  137.         if t[count+2] == "and" then
  138.             count = count + 3
  139.         else
  140.             break
  141.         end
  142.     end
  143.     return bindings
  144. end
  145.  
  146. function evalline(t,spirit) --a spirit holds its variables, aka bindings
  147.     if type(tonumber(t)) == "number" then
  148.         return tonumber(t)
  149.     elseif type(t) == "string" then
  150.         if t:sub(1,1) == '"' and t:sub(#t,#t) == '"' then
  151.             return t:sub(2,#t-1)
  152.         elseif spirit.bindings[t] ~= nil then
  153.             return spirit.bindings[t]
  154.         else
  155.             for k,v in pairs(spirit.bindings) do print(k,v) end
  156.             error("unknown binding "..t..#t..tostring(spirit.bindings[t]))
  157.         end
  158.     elseif type(t) ~= "table" then
  159.         error("wrong type "..type(t))
  160.     elseif t[1] == "conjure" then
  161.         if t[2] == "empty" then
  162.             return conjureempty()
  163.         else
  164.             local spell = evalline(t[2],spirit)
  165.             return conjurecopy(spell)   --you might make a copy of a spell, for some reason
  166.         end
  167.     elseif t[1] == "enchant" then
  168.         local spell = evalline(t[2],spirit)
  169.         enchant(spell, slice(t,3))  --the line ain't checked? only when executed? u avin a giggle m8?
  170.     elseif t[1] == "bindself" then
  171.         local exists = spirit.bindings[t[2]]
  172.         if exists then
  173.             error("bindself: "..t[2].." already binded")
  174.         end
  175.         spirit.bindings[t[2]] = evalline(slice(t,3),spirit)
  176.     elseif t[1] == "bind" then
  177.         local spr = evalline(t[2],spirit)
  178.         local exists = spr.bindings[t[3]]
  179.         if exists then
  180.             error("bind: "..t[3].." already binded")
  181.         end
  182.         spr.bindings[t[3]] = evalline(slice(t,4),spirit)
  183.     elseif t[1] == "from" then  --you can get the value of a bind from a different spirit
  184.         local spr = evalline(t[2],spirit)
  185.         return spr.bindings[t[3]]
  186.     elseif t[1] == "at" then    --to be used with forms, which are also the listguys (why??)
  187.         local sprorform = evalline(t[2],spirit)
  188.         local n = evalline(t[3],spirit)
  189.         return sprorform.spells[n]
  190.     elseif t[1] == "setat" then
  191.         local sprorform = evalline(t[2],spirit)
  192.         local n = evalline(t[3],spirit)
  193.         local v = evalline(t[4],spirit)
  194.         setat(sprorform,n,v)
  195.     elseif mymath2[t[1]] then
  196.         local a = evalline(t[2],spirit)
  197.         local b = evalline(t[3],spirit)
  198.         return mymath2[t[1]](a,b)
  199.     elseif mymath1[t[1]] then
  200.         local a = evalline(t[2],spirit)
  201.         return mymath1[t[1]](a)
  202.     elseif t[1] == "set" then   --just.. why?
  203.         --  this aint scheme fuk u
  204.         --local exists = spirit.bindings[t[2]]
  205.         --if not exists then
  206.         --  error("set: "..t[2].." not already binded")
  207.         --end
  208.         spirit.bindings[t[2]] = evalline(slice(t,3),spirit)
  209.     elseif t[1] == "summon" then
  210.         local spell = evalline(t[2],spirit)
  211.         local bindings = {}
  212.         if t[3] == "with" then
  213.             bindings = processwith(slice(t,4),spirit)
  214.         end
  215.         local spr = summon(spell,bindings)  --summon only adds it to the list, but doesnt do anything yet
  216.         bindings.summoner = spirit
  217.         spirit.halt=true    --when you summon, you're halted
  218.         return spr
  219.     --elseif t[1] == "summonhold" then
  220.     --  local spell = evalline(t[2],spirit)
  221.     --  local bindings = {summoner=spirit}
  222.     --  if t[3] == "with" then
  223.     --      bindings = processwith(slice(t,4),spirit)
  224.     --      bindings.summoner=spirit
  225.     --  end
  226.     --  local spr = summonhold(spell,bindings)  --summonhold halts everything, evaling the spirit continuously until it is unsummoned
  227.     --  return spr.rturn
  228.     elseif t[1] == "unsummon" then
  229.         local spr = evalline(t[2],spirit)
  230.         unsummon(spr)
  231.         if t[3] == "with" then  --this only has meaning if its a "unsummon self"
  232.             spr.rturn = evalline(t[4],spirit)
  233.         end
  234.     elseif t[1] == "return" then
  235.         local spr = evalline(t[2],spirit)
  236.         return spr.rturn
  237.     elseif t[1] == "if" then    --oh god, if wont work without parentheses and =,>,<,etc
  238.         local cond = evalline(t[2],spirit)
  239.         if cond then
  240.             return evalline(slice(t,3),spirit)
  241.         end
  242.     elseif t[1] == "print" then --dunno how i'll do this, eval t[2] or slice(t,2)? for now i'll use slice
  243.         local s
  244.         if #t == 2 then
  245.             s = evalline(t[2],spirit)
  246.         else
  247.             s = evalline(slice(t,2),spirit)
  248.         end
  249.         print(s)
  250.     elseif t[1] == "read" then
  251.         return io.read()
  252.     elseif t[1] == "skip" then
  253.         local n
  254.         if #t == 2 then
  255.             n = evalline(t[2],spirit)
  256.         else
  257.             n = evalline(slice(t,2),spirit)
  258.         end
  259.         spirit.p = spirit.p+n
  260.     elseif t[1] and not t[2] then   --something went wrong, sliced instead of using t[x]? quickfix
  261.         return evalline(t[1],spirit)
  262.     end
  263. end
  264.  
  265. function mydofile(s)
  266.     local spells = parsefile(s)
  267.     local mainform = conjureempty() --spells are forms but I should call spells' spells enchantments dunno
  268.     mainform.spells = spells
  269.     enchant(mainform,{"unsummon","self"})   --so it will only run once
  270.     summon(mainform,{})
  271.     dospirits()
  272.     return "hehe"
  273. end
  274.  
  275. function mydofilename(filename)
  276.     spiritlist={}   --need to clear it
  277.     spiritcount=0
  278.     local file = io.open(filename,"r")
  279.     local s = file:read("*a")
  280.     mydofile(s)
  281. end
  282.  
  283. function dospirits()    --here's where the shit gets done
  284.     while true do
  285.         local sprcount = 0  --it's different from spiritcount up there /\, that other is like an id count
  286.         for k,spirit in pairs(spiritlist) do
  287.             if not spirit.halt then
  288.                 evalspirit(spirit)
  289.             end
  290.                 sprcount = sprcount+1
  291.         end
  292.         if sprcount == 0 then   --no more spirits alive, why should we keep running?
  293.             break
  294.         end
  295.     end
  296. end
  297.  
  298. function evalspirit(spirit)
  299.     --while spirit.p <= #spirit.spells do
  300.         if spirit.dead then --todo:unhalt summoner
  301.             --break
  302.         end
  303.         evalline(spirit.spells[spirit.p],spirit)
  304.         spirit.p = spirit.p+1
  305.     --end
  306.     if spirit.p > #spirit.spells then
  307.         spirit.p=1
  308.     end
  309.     --spirit.bindings.firstloop = false
  310. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement