aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2018-10-29 08:35:53 +0000
committers-ol <s-ol@users.noreply.github.com>2018-10-29 08:35:53 +0000
commit27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e (patch)
treeac703b9f84c1c8e4666d039a880a2af91c450c4a
parentmove duct_tape to lib (diff)
downloadmmm-27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e.tar.gz
mmm-27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e.zip
better conversion inverence for mmmfs
-rw-r--r--Tupfile1
-rw-r--r--app/mmmfs/browser.moon5
-rw-r--r--app/mmmfs/conversion.moon121
-rw-r--r--app/mmmfs/init.moon221
-rw-r--r--app/mmmfs/tree/gallery.moon (renamed from app/mmmfs/gallery.moon)8
-rw-r--r--app/mmmfs/tree/init.moon (renamed from app/mmmfs/tree.moon)6
-rw-r--r--app/mmmfs/tree/twisted.moon (renamed from app/mmmfs/twisted.moon)0
-rw-r--r--lib/component.client.moon1
-rw-r--r--lib/init.client.moon21
-rw-r--r--lib/init.server.moon22
10 files changed, 220 insertions, 186 deletions
diff --git a/Tupfile b/Tupfile
index bcd9563..e555914 100644
--- a/Tupfile
+++ b/Tupfile
@@ -9,6 +9,7 @@ preload app app/tags lib
CLIENT += app/*.moon
CLIENT += app/tags/*.moon
CLIENT += app/mmmfs/*.moon
+CLIENT += app/mmmfs/tree/*.moon
CLIENT += lib/*.client.moon
CLIENT += lib/*.shared.moon
diff --git a/app/mmmfs/browser.moon b/app/mmmfs/browser.moon
index 50da38b..427d952 100644
--- a/app/mmmfs/browser.moon
+++ b/app/mmmfs/browser.moon
@@ -78,8 +78,9 @@ class Browser
active = @active\get!
ok, res = pcall ->
- val, key = active\get prop.name, prop.type
- CONVERT 'mmm/dom', val, key
+ -- val, key = active\get prop.name, prop.type
+ -- CONVERT 'mmm/dom', val, key
+ active\get prop.name, 'mmm/dom'
if ok and res
res
diff --git a/app/mmmfs/conversion.moon b/app/mmmfs/conversion.moon
new file mode 100644
index 0000000..a670e2e
--- /dev/null
+++ b/app/mmmfs/conversion.moon
@@ -0,0 +1,121 @@
+import text, code from require 'lib.html'
+import tohtml from require 'lib.component'
+
+-- limit function to one argument
+single = (func) -> (val) -> func val
+
+-- list of converts
+-- converts each have
+-- * inp - input type. can capture subtypes using `(.+)`
+-- * out - output type. can substitute subtypes from inp with %1, %2 etc.
+-- * transform - function (val: inp, fileder) -> val: out
+converts = {
+ {
+ inp: 'moon -> (.+)',
+ out: '%1',
+ transform: (val, fileder) -> val fileder
+ },
+ {
+ inp: 'text/plain',
+ out: 'mmm/dom',
+ transform: single text
+ },
+ {
+ inp: 'alpha',
+ out: 'mmm/dom',
+ transform: single code
+ },
+ {
+ inp: 'URL -> .*',
+ out: 'mmm/dom',
+ transform: single code
+ },
+ {
+ inp: 'mmm/component',
+ out: 'mmm/dom',
+ transform: single tohtml
+ },
+ {
+ inp: 'mmm/dom',
+ out: 'text/html',
+ transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML
+ },
+ {
+ inp: 'text/html',
+ out: 'mmm/dom',
+ transform: if MODE == 'SERVER'
+ (...) -> ...
+ else
+ (html) ->
+ tmp = document\createElement 'div'
+ tmp.innerHTML = html
+ if tmp.childElementCount == 1
+ tmp.firstChild
+ else
+ tmp
+ }
+}
+
+do
+ local markdown
+ if MODE == 'SERVER'
+ success, discount = pcall require, 'discount'
+ markdown = discount if success
+ else
+ markdown = window and window.marked and window\marked
+
+ if markdown
+ table.insert converts, {
+ inp: 'text/markdown',
+ out: 'text/html',
+ transform: (val) ->
+ html = markdown val
+ warn html
+ html
+ }
+
+count = (base, pattern='->') -> select 2, base\gsub pattern, ''
+escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$"
+
+-- attempt to find a conversion path from 'have' to 'want'
+-- * have - start type string or list of type strings
+-- * want - stop type string
+-- * limit - limit conversion amount
+-- returns a list of conversion steps
+get_conversions = (want, have, limit=3) ->
+ assert have, 'need starting type(s)'
+
+ if 'string' == type have
+ have = { have }
+
+ assert #have > 0, 'need starting type(s) (list was empty)'
+
+ iterations = limit + math.max table.unpack [count type for type in *have]
+ have = [{ :start, rest: start, conversions: {} } for start in *have]
+
+ for i=1, iterations
+ next_have, c = {}, 1
+ for { :start, :rest, :conversions } in *have
+ if want == rest
+ return conversions, start
+ else
+ for convert in *converts
+ inp = escape_inp convert.inp
+ matches = { rest\match inp }
+ continue unless #matches > 0
+ result = rest\gsub inp, convert.out
+ if result
+ next_have[c] = {
+ :start,
+ rest: result,
+ conversions: { convert, table.unpack conversions }
+ }
+ c += 1
+
+ have = next_have
+ return unless #have > 0
+
+{
+ :converts
+ :get_conversions
+}
diff --git a/app/mmmfs/init.moon b/app/mmmfs/init.moon
index 1f2d2f6..19cb028 100644
--- a/app/mmmfs/init.moon
+++ b/app/mmmfs/init.moon
@@ -1,143 +1,35 @@
-export ^
-
--- list of interps
--- interp signature is (fileder, value) -> value
-interps = {
- moon: (method) => method @
-}
-
-split = (str, delim='->') ->
- return {}, str if nil == str\find delim
+require = relative ...
+import get_conversions from require '.conversion'
- -- @TODO interp chain?
- interp, rest = str\match ' *(%w+) *-> *(.*)'
- { interp }, rest
+export ^
-- Key of a Fileder Property
-- contains:
-- * @name - key name or '' for main content
--- * @type - final type after interps
--- * @interps - array describing interp chain
+-- * @type - type string (type -> type -> type)
class Key
-- instantiate from table w/ keys described above
-- or string like 'name: interp -> interp -> type' (name + interps optional)
- new: (opts) =>
- if 'string' == type opts
- @name, rest = opts\match '(%w+): *(.+)'
+ new: (opts, second) =>
+ if 'string' == type second
+ @name, @type = (opts or ''), second
+ elseif 'string' == type opts
+ @name, @type = opts\match '(%w+): *(.+)'
if not @name
@name = ''
- rest = opts
- @interps, @type = split rest, '->'
+ @type = opts
elseif 'table' == type opts
@name = opts.name
- @type = assert opts.type, 'no type given'
- @interps = opts.interps or {}
+ @type = opts.type
else
- error 'wrong argument type'
-
- -- get a function that interpretes a raw value according to @interps
- -- and returns a value of @type
- -- overrides is a map of interp overrides
- get_interp: (overrides={}) =>
- return ((val) => val) if #@interps == 0
-
- assert #@interps == 1, 'not supported rn' -- @TODO
- _name = @interps[1]
-
- return overrides[_name] if overrides and overrides[_name]
-
- assert overrides[_name] or interps[_name], "interp not found: '#{_name}'"
+ error "wrong argument type: #{type opts}, #{type second}"
-- format as a string (see constructor)
tostring: =>
- list = { table.unpack @interps }
- table.insert list, @type
-
- type = table.concat list, ' -> '
-
if @name == ''
- type
+ @type
else
- "#{@name}: #{type}"
-
-
-import text, code from require 'lib.html'
-import tohtml from require 'lib.component'
-
--- list of converts
--- converts each have
--- * inp - input type
--- * out - output type
--- * transform - function (inp) -> out
-converts = {
- {
- inp: 'text/plain',
- out: 'mmm/dom',
- transform: text
- },
- {
- inp: 'alpha',
- out: 'mmm/dom',
- transform: code
- },
- {
- inp: 'mmm/dom',
- out: 'text/html',
- transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML
- },
- {
- inp: 'mmm/component',
- out: 'mmm/dom',
- transform: tohtml
- },
- {
- -- @TODO this chained rule *should* be inferred, but that's way too hot rn
- inp: 'mmm/component',
- out: 'text/html',
- transform: (node) ->
- node = tohtml node
- if MODE == 'SERVER' then node else node.outerHTML
- },
-}
-
-table.insert converts, {
- inp: 'text/html',
- out: 'mmm/dom',
- transform: if MODE == 'SERVER'
- (...) -> ...
- else
- (html) ->
- tmp = document\createElement 'div'
- tmp.innerHTML = html
- tmp.firstChild
- }
-
-do
- local markdown
- if MODE == 'SERVER'
- success, discount = pcall require, 'discount'
- markdown = discount if success
- else
- markdown = window and window\marked
-
- if markdown
- table.insert converts, {
- inp: 'text/markdown',
- out: 'text/html',
- transform: markdown,
- }
-
- -- @TODO chained w above
- table.insert converts, {
- inp: 'text/markdown',
- out: 'mmm/dom',
- transform: if MODE == 'SERVER'
- (md) -> markdown md
- else
- (md) ->
- with document\createElement 'div'
- .innerHTML = markdown md
- }
+ "#{@name}: #{@type}"
-- Fileder itself
-- contains:
@@ -158,69 +50,56 @@ class Fileder
-- find property key according to criteria, nil if no value or conversion path
-- * name - property name (optional: defaults to main content)
-- * type - wanted result type
- -- * convert - allow conversion (optional: default true)
- find: (name='', type, convert=true) =>
- if not type
- type = name
- name = ''
+ find: (...) =>
+ want = Key ...
- -- first pass, interps only
- for key, value in pairs @props
- continue unless key.name == name and key.type == type
+ -- filter props by name
+ matching = [ key for key in pairs @props when key.name == want.name ]
+ return unless #matching > 0
- return key
+ -- get shortest conversion path
+ shortest_path, start = get_conversions want.type, [ key.type for key in *matching ]
- if convert
- -- second pass, interps + converts
- for key, value in pairs @props
- continue unless key.name == name
+ if start
+ for key in *matching
+ if key.type == start
+ return key, shortest_path
- for { :inp, :out, :transform } in *converts
- return key if inp == key.type and out == type
+ error "couldn't find key after resolution?"
-- get property according to criteria, nil if no value or conversion path
-- * name - property name (optional: defaults to main content)
-- * type - wanted result type
- -- * overrides - map of interp overrides (optional)
- get: (name='', type, overrides) =>
- if not type
- type = name
- name = ''
+ get: (...) =>
+ want = Key ...
- key = @find name, type, not overrides
+ -- find matching key and shortest conversion path
+ key, conversions = @find want
if key
- interp = key\get_interp overrides
-
- return (interp @, @props[key]), key if key.type == type
+ value = @props[key]
- for { :inp, :out, :transform } in *converts
- return (transform interp @, @props[key]), key if inp == key.type and out == type
+ -- apply conversions (in reverse order)
+ for i=#conversions,1,-1
+ { :inp, :out, :transform } = conversions[i]
+ value = transform value, @
- nil, nil
+ value, key
- -- like get, throw if no value or conversion path
- gett: (name='', type, overrides) =>
- if not type
- type = name
- name = ''
+ -- like @get, throw if no value or conversion path
+ gett: (...) =>
+ want = Key ...
- val, key = @get name, type, overrides
- assert val, "node doesn't have value for #{name}:#{type}"
- val, key
+ value, key = @get want
+ assert value, "node doesn't have value for #{want\tostring!}"
+ value, key
-CONVERT = (type, val, key) ->
- return unless val and key
-
- if key.type == type
- val
- else
- for { :inp, :out, :transform } in *converts
- return transform val if inp == key.type and out == type
-
-require = relative ...
-import Browser from require '.browser'
root = require '.tree'
-
-BROWSER = Browser root
-append BROWSER.node
+if MODE == 'CLIENT'
+ import Browser from require '.browser'
+
+ export BROWSER
+ BROWSER = Browser root
+ append BROWSER.node
+else
+ append root\get 'mmm/dom'
diff --git a/app/mmmfs/gallery.moon b/app/mmmfs/tree/gallery.moon
index e1868d1..93ca58d 100644
--- a/app/mmmfs/gallery.moon
+++ b/app/mmmfs/tree/gallery.moon
@@ -1,7 +1,5 @@
import div, h1, a, img, br from require 'lib.html'
-URL = (url) => url
-
children = for i=1,100
id = math.floor math.random! * 200
Fileder {
@@ -16,13 +14,13 @@ props = {
'preview: moon -> mmm/dom': => div {
'the first pic as a little taste:',
br!,
- img src: @children[1]\get 'preview', 'image/png', :URL
+ img src: @children[1]\get 'preview', 'URL -> image/png'
}
'moon -> mmm/dom': =>
link = (child) -> a {
href: '#',
onclick: -> BROWSER\navigate { 'gallery', (child\get 'name', 'alpha'), nil },
- img src: child\gett 'preview', 'image/png', :URL
+ img src: child\gett 'preview', 'URL -> image/png'
}
content = [link child for child in *@children]
@@ -44,7 +42,7 @@ props = {
index\map (i) -> text " image ##{i} "
e.a 'next', href: '#', onclick: -> index\transform next
},
- index\map (i) -> img src: @children[i]\gett nil, 'image/png', :URL
+ index\map (i) -> img src: @children[i]\gett nil, 'URL -> image/png'
}
}
diff --git a/app/mmmfs/tree.moon b/app/mmmfs/tree/init.moon
index e270cf8..1d6a116 100644
--- a/app/mmmfs/tree.moon
+++ b/app/mmmfs/tree/init.moon
@@ -1,4 +1,4 @@
-require = relative ..., 1
+require = relative ...
Fileder {
-- main content
@@ -224,9 +224,7 @@ If you are reading this in the source, then c'mon, just scroll past and give me
-- preview is a lua/moonscript function that neturns an mmm/dom value
'preview: moon -> mmm/dom': =>
import img from require 'lib.html'
- img src: @gett nil, -- look for: main content
- 'image/png', -- with image type, and
- URL: (url) => url -- override URL interp to get raw URL
+ img src: @gett nil, 'URL -> image/png' -- look for main content with 'URL to png' type
}
Fileder {
diff --git a/app/mmmfs/twisted.moon b/app/mmmfs/tree/twisted.moon
index ec3fa83..ec3fa83 100644
--- a/app/mmmfs/twisted.moon
+++ b/app/mmmfs/tree/twisted.moon
diff --git a/lib/component.client.moon b/lib/component.client.moon
index 617deb5..af0b38a 100644
--- a/lib/component.client.moon
+++ b/lib/component.client.moon
@@ -102,6 +102,7 @@ class ReactiveElement
@node.style[k] = v
return
+ print "setting attr #{attr}"
@node[attr] = value
append: (child, last) =>
diff --git a/lib/init.client.moon b/lib/init.client.moon
index c1aea07..d39143d 100644
--- a/lib/init.client.moon
+++ b/lib/init.client.moon
@@ -5,8 +5,25 @@ window = js.global
{ :document, :console } = window
MODE = 'CLIENT'
-print = console\log
-warn = console\warn
+
+deep_tostring = (tbl, space='') ->
+ buf = space .. tostring tbl
+
+ return buf unless 'table' == type tbl
+
+ buf = buf .. ' {\n'
+ for k,v in pairs tbl
+ buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n"
+ buf = buf .. "#{space}}"
+ buf
+
+print = (...) ->
+ contents = [deep_tostring v for v in *{ ... } ]
+ console\log table.unpack contents
+
+warn = (...) ->
+ contents = [deep_tostring v for v in *{ ... } ]
+ console\warn table.unpack contents
package.path = '/?.shared.moon.lua;/?.client.moon.lua;/?.moon.lua;/?/init.moon.lua;/?.lua;/?/init.lua'
diff --git a/lib/init.server.moon b/lib/init.server.moon
index a91bd52..f81a2dc 100644
--- a/lib/init.server.moon
+++ b/lib/init.server.moon
@@ -1,9 +1,27 @@
-export MODE, warn, relative, append, on_client
+export MODE, print, warn, relative, append, on_client
MODE = 'SERVER'
+deep_tostring = (tbl, space='') ->
+ buf = space .. tostring tbl
+
+ return buf unless 'table' == type tbl
+
+ buf = buf .. ' {\n'
+ for k,v in pairs tbl
+ buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n"
+ buf = buf .. "#{space}}"
+ buf
+
+print = do
+ _print = print
+ (...) ->
+ contents = [deep_tostring v for v in *{ ... } ]
+ _print table.unpack contents
+
-- warning messages
warn = (...) ->
- io.stderr\write table.concat { ... }, '\t'
+ contents = [deep_tostring v for v in *{ ... } ]
+ io.stderr\write table.concat contents, '\t'
io.stderr\write '\n'
-- relative imports