require "lib/metaprogramming.nom" # Literals compile (true; yes) to: "true" compile (false; no) to: "false" compile (nil; null) to: "nil" compile (inf; infinity) to: "math.huge" compile (nan; NaN; not a number) to: "(0/0)" compile (pi; PI) to: "math.pi" compile (tau; TAU) to: "(2*math.pi)" compile (phi; PHI; golden ratio) to: "((1+math.sqrt(5))/2)" compile (nop; pass) to code: "" # Ternary operator compile (%if_expr if %condition else %else_expr) to: ".." |(function(nomsu, vars) # TODO: fix compiler bug that breaks this code if comments immediately follow ".." #.. Note: this uses a function instead of (condition and if_expr or else_expr) because that breaks if %if_expr is falsey. | if \(%condition) then | return \(%if_expr) | else | return \(%else_expr) | end |end)(nomsu, vars) # Indexing: compile (%obj's %key; %obj -> %key) to: "\(%obj as lua)[\(%key as lua)]" # Variable assignment operator, and += type versions compile (%var = %val) to code: "\(%var as lua) = \(%val as lua)" compile (%var += %val) to code: "\(%var as lua) += \(%val as lua)" compile (%var -= %val) to code: "\(%var as lua) -= \(%val as lua)" compile (%var *= %val) to code: "\(%var as lua) *= \(%val as lua)" compile (%var /= %val) to code: "\(%var as lua) /= \(%val as lua)" compile (%var ^= %val) to code: "\(%var as lua) ^= \(%val as lua)" compile (%var and= %val) to code: "\(%var as lua) = \(%var as lua) and\(%val as lua)" compile (%var or= %val) to code: "\(%var as lua) = \(%var as lua) or \(%val as lua)" compile (%var join= %val) to code: "\(%var as lua) = \(%var as lua) .. \(%val as lua)" compile (%var mod= %val) to code: "\(%var as lua) = \(%var as lua) % \(%val as lua)" %x =: 5 # Binary Operators lua block ".." |local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}} |for _,op in ipairs(binops) do | local nomsu_alias = op | if type(op) == 'table' then | nomsu_alias, op = unpack(op) | end | nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars) | return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")" | end), [["(\\(%a) ]]..op..[[ \\(%b))"]]) |end # TODO: implement OR, XOR, AND for multiple operands compile (%a OR %b; %a | %b) to: "bit32.bor(\(%a as lua), \(%b as lua))" compile (%a XOR %b) to: "bit32.bxor(\(%a as lua), \(%b as lua))" compile (%a AND %b; %a & %b) to: "bit32.band(\(%a as lua), \(%b as lua))" compile (NOT %; ~ %) to: "bit32.bnot(\(% as lua))" compile (%x LSHIFT %shift; %x << %shift) to: "bit32.lshift(\(%x as lua), \(%shift as lua))" compile (%x RSHIFT %shift) to: "bit32.rshift(\(%x as lua), \(%shift as lua))" compile (%x ARSHIFT %shift; %x >> %shift) to: "bit32.arshift(\(%x as lua), \(%shift as lua))" # == and != do equivalence checking, rather than identity checking compile (%a == %b) to: "nomsu.utils.equivalent(\(%a as lua), \(%b as lua))" compile (%a != %b) to: "(not nomsu.utils.equivalent(\(%a as lua), \(%b as lua)))" # Commutative Operators defined for up to 8 operands # TODO: work out solution for commutative operators using more clever macros lua block ".." |local max_operands = 8 |local comops = {"+","*","and","or"} |for _,_op in ipairs(comops) do | local op = _op | local spec = "%1 " | for n=2,max_operands do | spec = spec .." "..op.." %"..tostring(n) | nomsu:defmacro(spec, (function(nomsu, vars) | local bits = {} | for i=1,n do | table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)]))) | end | return "("..table.concat(bits, " "..op.." ")..")" | end)) | end |end # Chained compairsions (e.g. x < y <= z) are defined up to 3 operands lua block ".." |local max_operands = 3 |for _,chainers in ipairs({{"<","<="},{">",">="}}) do | local function recurse(chainers, chain) # The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense | if #chain >= 2 then | local spec = "%1" | for i,op in ipairs(chain) do | spec = spec .. " "..op.." %"..tostring(i+1) | end # Chained comparisons need to be functions to avoid re-evaluating their arguments :\ | nomsu:def(spec, function(nomsu, vars) | for i,op in ipairs(chain) do | local a, b, result = vars[i], vars[i+1] | if op == "<" then result = a < b | elseif op == "<=" then result = a <= b | elseif op == ">" then result = a > b | elseif op == ">=" then result = a >= b end # Short circuit | if not result then return false end | end | end) | end | if #chain + 1 >= max_operands then return end | for _,c in ipairs(chainers) do | table.insert(chain, c) | recurse(chainers, chain) | table.remove(chain) | end | end | recurse(chainers, {}) |end # Unary operators compile (- %) to: "-(\(% as lua))" compile (not %) to: "not (\(% as lua))"