~technomancy/fennel

Support rshift, lshift, band, bxor, fix bnot v1 PROPOSED

Ambrose Bonnaire-Sergeant: 1
 Support rshift, lshift, band, bxor, fix bnot

 7 files changed, 107 insertions(+), 34 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~technomancy/fennel/patches/39700/mbox | git am -3
Learn more about email & git

[PATCH] Support rshift, lshift, band, bxor, fix bnot Export this patch

I can't seem to use fnlfmt correctly, or run `make test` successfully,
so the work is not entirely done.
---
 README.md         |  3 ++
 anticompiler.fnl  |  8 +++--
 lang/lexer.lua    | 23 +++++++++++++--
 lang/operator.lua |  8 +++--
 lang/parser.lua   |  2 +-
 test.lua          | 22 ++++++++++++++
 test_expected.fnl | 75 ++++++++++++++++++++++++++++++++---------------
 7 files changed, 107 insertions(+), 34 deletions(-)

diff --git a/README.md b/README.md
index 081d390..0e1ca87 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,9 @@ The Antifennel compiler assumes its input file is valid Lua 5.1; it does
not attempt to give good error messages when provided with files that
won't parse or support newer features of Lua.

Antifennel supports all [bitwise operators](https://www.lua.org/manual/5.3/manual.html#3.4.2)
introduced in Lua 5.3.

Antifennel will never emit variadic operators, hashfns, or pattern
matches, even in cases that would result in much better code.

diff --git a/anticompiler.fnl b/anticompiler.fnl
index 49ef239..66cdf4f 100644
--- a/anticompiler.fnl
+++ b/anticompiler.fnl
@@ -115,14 +115,16 @@
              (.. "return " (table.concat (map args view) ", "))))))

(fn binary [compile scope {: left : right : operator} ast]
  (let [operators {:== := "~=" :not= "#" :length "~" :bnot}]
  (let [operators {:== := "~=" :not= "#" :length "~" :bxor
                   :<< :lshift :>> :rshift :& :band :| :bor}]
    (list (sym (or (. operators operator) operator))
          (compile scope left)
          (compile scope right))))

(fn unary [compile scope {: argument : operator} ast]
  (list (sym operator)
        (compile scope argument)))
  (let [operators {"~" :bnot}]
    (list (sym (or (. operators operator) operator))
          (compile scope argument))))

(fn call [compile scope {: arguments : callee}]
  (list (compile scope callee) (unpack (map arguments (partial compile scope)))))
diff --git a/lang/lexer.lua b/lang/lexer.lua
index 444b364..aef60dd 100644
--- a/lang/lexer.lua
+++ b/lang/lexer.lua
@@ -14,7 +14,8 @@ local ReservedKeyword = {['and'] = 1, ['break'] = 2, ['do'] = 3, ['else'] = 4, [
local uint64, int64 = ffi.typeof('uint64_t'), ffi.typeof('int64_t')
local complex = ffi.typeof('complex')

local TokenSymbol = { TK_ge = '>=', TK_le = '<=' , TK_concat = '..', TK_eq = '==', TK_ne = '~=', TK_eof = '<eof>' }
local TokenSymbol = { TK_ge = '>=', TK_le = '<=' , TK_concat = '..', TK_eq = '==', TK_ne = '~=', TK_eof = '<eof>',
                      TK_shl = '<<', TK_shr = '>>' }

local function token2str(tok)
    if string.match(tok, "^TK_") then
@@ -422,10 +423,26 @@ local function llex(ls)
            if ls.current ~= '=' then return '=' else nextchar(ls); return 'TK_eq' end
        elseif current == '<' then
            nextchar(ls)
            if ls.current ~= '=' then return '<' else nextchar(ls); return 'TK_le' end
            if ls.current == '=' then
              nextchar(ls);
              return 'TK_le'
            elseif ls.current == '<' then
              nextchar(ls);
              return 'TK_shl'
            else
              return '<'
            end
        elseif current == '>' then
            nextchar(ls)
            if ls.current ~= '=' then return '>' else nextchar(ls); return 'TK_ge' end
            if ls.current == '=' then
              nextchar(ls);
              return 'TK_ge'
            elseif ls.current == '>' then
              nextchar(ls);
              return 'TK_shr'
            else
              return '>'
            end
        elseif current == '~' then
            nextchar(ls)
            if ls.current ~= '=' then return '~' else nextchar(ls); return 'TK_ne' end
diff --git a/lang/operator.lua b/lang/operator.lua
index b80717a..616935e 100644
--- a/lang/operator.lua
+++ b/lang/operator.lua
@@ -2,14 +2,16 @@
-- (left priority) * 256 + (right priority)
-- modulus is your friend
local binop = {
    ['+']  = 6 * 256 + 6, ['-']  = 6 * 256 + 6, ['*'] = 7 * 256 + 7, ['/'] = 7 * 256 + 7, ['%'] = 7 * 256 + 7,
    ['^']  = 10* 256 + 9, ['..'] = 5 * 256 + 4, -- POW CONCAT (right associative)
    ['+']  = 9 * 256 + 9, ['-']  = 9 * 256 + 9, ['*'] = 10 * 256 + 10, ['/'] = 10 * 256 + 10, ['%'] = 10 * 256 + 10,
    ['^']  = 13* 256 +12, ['..'] = 8 * 256 + 7, -- POW CONCAT (right associative)
    ['<<'] = 7 * 256 + 7, ['>>'] = 7 * 256 + 7,
    ['&']  = 6 * 256 + 6, ['~']  = 5 * 256 + 5, ['|']  = 4 * 256 + 4,
    ['=='] = 3 * 256 + 3, ['~='] = 3 * 256 + 3,
    ['<']  = 3 * 256 + 3, ['>='] = 3 * 256 + 3, ['>'] = 3 * 256 + 3, ['<='] = 3 * 256 + 3,
    ['and']= 2 * 256 + 2, ['or'] = 1 * 256 + 1,
}

local unary_priority = 8
local unary_priority = 12

-- Pseudo priority of a simple identifier. Should be higher than any
-- others operator's priority.
diff --git a/lang/parser.lua b/lang/parser.lua
index 6a468e8..0afb481 100644
--- a/lang/parser.lua
+++ b/lang/parser.lua
@@ -139,7 +139,7 @@ end

function expr_unop(ast, ls)
    local tk = ls.token
    if tk == 'TK_not' or tk == '-' or tk == '#' then
    if tk == 'TK_not' or tk == '-' or tk == '#' or tk == '~' then
        local line = ls.linenumber
        ls:next()
        local v = expr_binop(ast, ls, operator.unary_priority)
diff --git a/test.lua b/test.lua
index fc56fd1..718c456 100644
--- a/test.lua
+++ b/test.lua
@@ -101,4 +101,26 @@ do
   local isolated = 9
end

assert ((50 >> 1) == 25)
assert ((1 << 2) == 4)
assert ((50 & 25) == 16)
assert ((1 ~ 2) == 3)
assert ((1 | 6) == 7)
assert ((#{1} | 6) == 7)
assert ((100 | 99 >> 2 << 1) == 116)
assert ((100 | (99 >> 2) << 1) == 116)
assert ((((100 | 99) >> 2) << 1) == 50)
assert (((100 | (99 >> 2)) << 1) == 248)
assert ((100 | (99 >> (2 << 1))) == 102)
assert (59 >> 2 << 127 == 0)
assert ((59 >> 2) << 127 == 0)
assert (59 >> (2 << 127) == 59)
assert (50 >> 2 >> 1 == 6)
assert ((50 >> 2) >> 1 == 6)
assert (50 >> (2 >> 1) == 25)
assert ((59 >> 2) << 127 == 0)
assert (59 >> (2 << 127) == 59)
assert ((~ 1) == -2)
assert ((1 + (~ 1)) == -1)

return (f123("path") or {"a", "b", "c"}).mode
diff --git a/test_expected.fnl b/test_expected.fnl
index f40e46c..b707e53 100644
--- a/test_expected.fnl
+++ b/test_expected.fnl
@@ -11,8 +11,7 @@

(: :abcdef :match :abc)

(local t {:t2 {:f (fn [x]
                    x)}})
(local t {:t2 {:f (fn [x] x)}})

(: (. t :t2) :f)

@@ -23,10 +22,7 @@

(noprint (.. (or base "") "_" append "_"))

(fn f [x y]
  (var (z zz) (values 9 8))
  (local b 99)
  (set-forcibly! x 5)
(fn f [x y] (var (z zz) (values 9 8)) (local b 99) (set-forcibly! x 5)
  (set z 0)
  (global a 1)
  (set y.y false))
@@ -42,14 +38,10 @@
        y 20]
    (+ x y)))

(noprint ((fn []
            (let [x 1]
              x))))
(noprint ((fn [] (let [x 1] x))))

(fn f123 [/_1]
  (let [/_0 :zero]
    (noprint (.. /_0 /_1))
    (values {} 2 3)))
  (let [/_0 :zero] (noprint (.. /_0 /_1)) (values {} 2 3)))

(fn bcd [...]
  (let [t {1 :bcd 2 ... :a :value}]
@@ -71,24 +63,19 @@

(fn early-returns [some-var]
  (when true
    (let [___antifnl_rtn_1___ some-var]
      (lua "return ___antifnl_rtn_1___")))
    (let [___antifnl_rtn_1___ some-var] (lua "return ___antifnl_rtn_1___")))
  nil)

(local early-result (early-returns :success))

(assert (= early-result :success) early-result)

(for [outer 1 10]
  (for [inner 1 10 2]
    (noprint outer inner)))
(for [outer 1 10] (for [inner 1 10 2] (noprint outer inner)))

(fn dynamic-step []
  3)
(fn dynamic-step [] 3)

(for [dynamic 1 2 (dynamic-step)]
  (for [unnecessary-step 1 10]
    (noprint dynamic unnecessary-step)))
  (for [unnecessary-step 1 10] (noprint dynamic unnecessary-step)))

(print {1 1 2 2 :a 3})

@@ -96,8 +83,48 @@

(set (chr src.line src.from-macro?) (values filename line true))

(let [isolated 9]
  nil)
(let [isolated 9] nil)

(. (or (f123 :path) [:a :b :c]) :mode)
(assert (= (rshift 50 1) 25))

(assert (= (lshift 1 2) 4))

(assert (= (band 50 25) 16))

(assert (= (bxor 1 2) 3))

(assert (= (bor 1 6) 7))

(assert (= (bor (length [1]) 6) 7))

(assert (= (bor 100 (lshift (rshift 99 2) 1)) 116))

(assert (= (bor 100 (lshift (rshift 99 2) 1)) 116))

(assert (= (lshift (rshift (bor 100 99) 2) 1) 50))

(assert (= (lshift (bor 100 (rshift 99 2)) 1) 248))

(assert (= (bor 100 (rshift 99 (lshift 2 1))) 102))

(assert (= (lshift (rshift 59 2) 127) 0))

(assert (= (lshift (rshift 59 2) 127) 0))

(assert (= (rshift 59 (lshift 2 127)) 59))

(assert (= (rshift (rshift 50 2) 1) 6))

(assert (= (rshift (rshift 50 2) 1) 6))

(assert (= (rshift 50 (rshift 2 1)) 25))

(assert (= (lshift (rshift 59 2) 127) 0))

(assert (= (rshift 59 (lshift 2 127)) 59))

(assert (= (bnot 1) (- 2)))

(assert (= (+ 1 (bnot 1)) (- 1)))

(. (or (f123 :path) [:a :b :c]) :mode)
-- 
2.37.1 (Apple Git-137.1)
Ambrose Bonnaire-Sergeant <abonnairesergeant@gmail.com> writes: