daily pastebin goal
20%
SHARE
TWEET

Magic interpreter in Lua

a guest Apr 13th, 2013 126 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top