wlang 0.10.2 → 2.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. data/CHANGELOG.md +3 -121
  2. data/Gemfile +23 -1
  3. data/Gemfile.lock +32 -28
  4. data/LICENCE.md +18 -21
  5. data/Manifest.txt +4 -5
  6. data/README.md +100 -174
  7. data/Rakefile +1 -13
  8. data/bin/wlang +3 -29
  9. data/lib/wlang.rb +21 -394
  10. data/lib/wlang/command.rb +94 -0
  11. data/lib/wlang/compiler.rb +78 -0
  12. data/lib/wlang/compiler/autospacing.rb +60 -0
  13. data/lib/wlang/compiler/dialect_enforcer.rb +91 -0
  14. data/lib/wlang/compiler/filter.rb +32 -0
  15. data/lib/wlang/compiler/grammar.citrus +67 -0
  16. data/lib/wlang/compiler/parser.rb +26 -0
  17. data/lib/wlang/compiler/proc_call_removal.rb +15 -0
  18. data/lib/wlang/compiler/static_merger.rb +28 -0
  19. data/lib/wlang/compiler/strconcat_flattener.rb +25 -0
  20. data/lib/wlang/compiler/to_ruby_abstraction.rb +22 -0
  21. data/lib/wlang/compiler/to_ruby_code.rb +55 -0
  22. data/lib/wlang/dialect.rb +40 -237
  23. data/lib/wlang/dialect/dispatching.rb +51 -0
  24. data/lib/wlang/dialect/evaluation.rb +30 -0
  25. data/lib/wlang/dialect/tags.rb +50 -0
  26. data/lib/wlang/dummy.rb +32 -0
  27. data/lib/wlang/html.rb +106 -0
  28. data/lib/wlang/loader.rb +6 -0
  29. data/lib/wlang/mustang.rb +90 -0
  30. data/lib/wlang/scope.rb +57 -0
  31. data/lib/wlang/scope/binding_scope.rb +18 -0
  32. data/lib/wlang/scope/object_scope.rb +25 -0
  33. data/lib/wlang/scope/proxy_scope.rb +18 -0
  34. data/lib/wlang/scope/root_scope.rb +24 -0
  35. data/lib/wlang/template.rb +16 -86
  36. data/lib/wlang/version.rb +9 -8
  37. data/spec/fixtures/dialect/foobar.rb +31 -0
  38. data/spec/fixtures/dialect/upcasing.rb +13 -0
  39. data/spec/fixtures/templates/hello.tpl +1 -0
  40. data/spec/integration/examples/1-basics.txt +65 -0
  41. data/spec/integration/examples/2-imperative.txt +51 -0
  42. data/spec/integration/examples/3-partials.txt +76 -0
  43. data/spec/integration/examples/4-recursion.txt +16 -0
  44. data/spec/integration/html/test_ampersand.rb +15 -0
  45. data/spec/integration/html/test_bang.rb +38 -0
  46. data/spec/integration/html/test_caret.rb +33 -0
  47. data/spec/integration/html/test_dollar.rb +16 -0
  48. data/spec/integration/html/test_greater.rb +23 -0
  49. data/spec/integration/html/test_modulo.rb +16 -0
  50. data/spec/integration/html/test_plus.rb +48 -0
  51. data/spec/integration/html/test_question.rb +33 -0
  52. data/spec/integration/html/test_sharp.rb +21 -0
  53. data/spec/integration/html/test_slash.rb +16 -0
  54. data/spec/integration/html/test_star.rb +37 -0
  55. data/spec/integration/test_dummy.rb +51 -0
  56. data/spec/integration/test_examples.rb +29 -0
  57. data/spec/integration/test_mustang.rb +120 -0
  58. data/spec/integration/test_readme.rb +56 -0
  59. data/spec/integration/test_upcasing.rb +22 -0
  60. data/spec/spec_helper.rb +62 -1
  61. data/spec/test_wlang.rb +101 -0
  62. data/spec/unit/compiler/autospacing/test_right_strip.rb +30 -0
  63. data/spec/unit/compiler/autospacing/test_unindent.rb +30 -0
  64. data/spec/unit/compiler/test_dialect_enforcer.rb +168 -0
  65. data/spec/unit/compiler/test_grammar.rb +207 -0
  66. data/spec/unit/compiler/test_parser.rb +69 -0
  67. data/spec/unit/compiler/test_proc_call_removal.rb +24 -0
  68. data/spec/unit/compiler/test_static_merger.rb +29 -0
  69. data/spec/unit/compiler/test_strconcat_flattener.rb +30 -0
  70. data/spec/unit/compiler/test_to_ruby_abstraction.rb +59 -0
  71. data/spec/unit/compiler/test_to_ruby_code.rb +24 -0
  72. data/spec/unit/dialect/test_compile.rb +52 -0
  73. data/spec/unit/dialect/test_dispatching.rb +19 -0
  74. data/spec/unit/dialect/test_evaluate.rb +41 -0
  75. data/spec/unit/dialect/test_render.rb +33 -0
  76. data/spec/unit/dialect/test_tags.rb +32 -0
  77. data/spec/unit/dialect/test_with_scope.rb +18 -0
  78. data/spec/unit/scope/test_binding_scope.rb +27 -0
  79. data/spec/unit/scope/test_coerce.rb +22 -0
  80. data/spec/unit/scope/test_object_scope.rb +38 -0
  81. data/spec/unit/scope/test_proxy_scope.rb +22 -0
  82. data/spec/unit/scope/test_root_scope.rb +22 -0
  83. data/spec/unit/test_assumptions.rb +29 -0
  84. data/spec/unit/test_scope.rb +57 -0
  85. data/tasks/debug_mail.rake +42 -45
  86. data/tasks/gem.rake +22 -17
  87. data/tasks/spec_test.rake +9 -17
  88. data/tasks/unit_test.rake +11 -12
  89. data/tasks/yard.rake +13 -13
  90. data/wlang.gemspec +36 -32
  91. data/wlang.noespec +27 -35
  92. metadata +268 -451
  93. data/doc/specification/about.rdoc +0 -61
  94. data/doc/specification/analytics.wtpl +0 -13
  95. data/doc/specification/dialect.wtpl +0 -14
  96. data/doc/specification/dialects.wtpl +0 -3
  97. data/doc/specification/examples.rb +0 -3
  98. data/doc/specification/glossary.wtpl +0 -14
  99. data/doc/specification/hosting.rdoc +0 -0
  100. data/doc/specification/overview.rdoc +0 -116
  101. data/doc/specification/rulesets.wtpl +0 -87
  102. data/doc/specification/specification.css +0 -53
  103. data/doc/specification/specification.html +0 -1690
  104. data/doc/specification/specification.js +0 -8
  105. data/doc/specification/specification.wtpl +0 -42
  106. data/doc/specification/specification.yml +0 -432
  107. data/doc/specification/symbols.wtpl +0 -16
  108. data/lib/wlang/dialect_dsl.rb +0 -141
  109. data/lib/wlang/dialect_loader.rb +0 -74
  110. data/lib/wlang/dialects/bluecloth_dialect.rb +0 -16
  111. data/lib/wlang/dialects/coderay_dialect.rb +0 -45
  112. data/lib/wlang/dialects/hosted_dialect.rb +0 -50
  113. data/lib/wlang/dialects/plain_text_dialect.rb +0 -69
  114. data/lib/wlang/dialects/rdoc_dialect.rb +0 -33
  115. data/lib/wlang/dialects/redcloth_dialect.rb +0 -16
  116. data/lib/wlang/dialects/ruby_dialect.rb +0 -118
  117. data/lib/wlang/dialects/sql_dialect.rb +0 -38
  118. data/lib/wlang/dialects/standard_dialects.rb +0 -181
  119. data/lib/wlang/dialects/xhtml_dialect.rb +0 -63
  120. data/lib/wlang/dialects/yaml_dialect.rb +0 -30
  121. data/lib/wlang/encoder.rb +0 -62
  122. data/lib/wlang/encoder_set.rb +0 -122
  123. data/lib/wlang/errors.rb +0 -80
  124. data/lib/wlang/ext/hash_methodize.rb +0 -13
  125. data/lib/wlang/ext/string.rb +0 -44
  126. data/lib/wlang/hash_scope.rb +0 -89
  127. data/lib/wlang/hosted_language.rb +0 -146
  128. data/lib/wlang/intelligent_buffer.rb +0 -94
  129. data/lib/wlang/parser.rb +0 -332
  130. data/lib/wlang/parser_state.rb +0 -94
  131. data/lib/wlang/rule.rb +0 -66
  132. data/lib/wlang/rule_set.rb +0 -106
  133. data/lib/wlang/rulesets/basic_ruleset.rb +0 -83
  134. data/lib/wlang/rulesets/buffering_ruleset.rb +0 -115
  135. data/lib/wlang/rulesets/context_ruleset.rb +0 -111
  136. data/lib/wlang/rulesets/encoding_ruleset.rb +0 -73
  137. data/lib/wlang/rulesets/imperative_ruleset.rb +0 -132
  138. data/lib/wlang/rulesets/ruleset_utils.rb +0 -317
  139. data/lib/wlang/wlang_command.rb +0 -51
  140. data/lib/wlang/wlang_command_options.rb +0 -163
  141. data/spec/basic_object.spec +0 -40
  142. data/spec/coderay_dialect.spec +0 -8
  143. data/spec/dialect/apply_post_transform.spec +0 -16
  144. data/spec/global_extensions.rb +0 -2
  145. data/spec/hash_scope.spec +0 -76
  146. data/spec/redcloth_dialect.spec +0 -24
  147. data/spec/test_all.rb +0 -8
  148. data/spec/wlang.spec +0 -53
  149. data/spec/wlang_spec.rb +0 -8
  150. data/spec/xhtml_dialect.spec +0 -22
  151. data/tasks/genspec.rake +0 -5
  152. data/test/blackbox/basic/execution_1.exp +0 -1
  153. data/test/blackbox/basic/execution_1.tpl +0 -1
  154. data/test/blackbox/basic/execution_2.exp +0 -1
  155. data/test/blackbox/basic/execution_2.tpl +0 -1
  156. data/test/blackbox/basic/execution_3.exp +0 -1
  157. data/test/blackbox/basic/execution_3.tpl +0 -1
  158. data/test/blackbox/basic/execution_4.exp +0 -1
  159. data/test/blackbox/basic/execution_4.tpl +0 -1
  160. data/test/blackbox/basic/inclusion_1.exp +0 -1
  161. data/test/blackbox/basic/inclusion_1.tpl +0 -1
  162. data/test/blackbox/basic/inclusion_2.exp +0 -1
  163. data/test/blackbox/basic/inclusion_2.tpl +0 -1
  164. data/test/blackbox/basic/injection_1.exp +0 -1
  165. data/test/blackbox/basic/injection_1.tpl +0 -1
  166. data/test/blackbox/basic/injection_2.exp +0 -1
  167. data/test/blackbox/basic/injection_2.tpl +0 -1
  168. data/test/blackbox/basic/modulation_1.exp +0 -1
  169. data/test/blackbox/basic/modulation_1.tpl +0 -1
  170. data/test/blackbox/basic/modulation_2.exp +0 -1
  171. data/test/blackbox/basic/modulation_2.tpl +0 -1
  172. data/test/blackbox/basic/recursive_app_1.exp +0 -1
  173. data/test/blackbox/basic/recursive_app_1.tpl +0 -1
  174. data/test/blackbox/basic/recursive_app_2.exp +0 -1
  175. data/test/blackbox/basic/recursive_app_2.tpl +0 -1
  176. data/test/blackbox/buffering/data_1.rb +0 -1
  177. data/test/blackbox/buffering/data_assignment_1.exp +0 -1
  178. data/test/blackbox/buffering/data_assignment_1.tpl +0 -1
  179. data/test/blackbox/buffering/data_assignment_2.exp +0 -1
  180. data/test/blackbox/buffering/data_assignment_2.tpl +0 -1
  181. data/test/blackbox/buffering/data_assignment_3.exp +0 -1
  182. data/test/blackbox/buffering/data_assignment_3.tpl +0 -1
  183. data/test/blackbox/buffering/data_assignment_4.exp +0 -1
  184. data/test/blackbox/buffering/data_assignment_4.tpl +0 -1
  185. data/test/blackbox/buffering/input_1.exp +0 -1
  186. data/test/blackbox/buffering/input_1.tpl +0 -1
  187. data/test/blackbox/buffering/input_2.exp +0 -1
  188. data/test/blackbox/buffering/input_2.tpl +0 -1
  189. data/test/blackbox/buffering/input_3.exp +0 -1
  190. data/test/blackbox/buffering/input_3.tpl +0 -1
  191. data/test/blackbox/buffering/input_inclusion.exp +0 -1
  192. data/test/blackbox/buffering/input_inclusion.tpl +0 -1
  193. data/test/blackbox/buffering/input_inclusion_1.exp +0 -0
  194. data/test/blackbox/buffering/input_inclusion_1.tpl +0 -1
  195. data/test/blackbox/buffering/input_inclusion_2.exp +0 -1
  196. data/test/blackbox/buffering/input_inclusion_2.tpl +0 -1
  197. data/test/blackbox/buffering/input_inclusion_3.exp +0 -1
  198. data/test/blackbox/buffering/input_inclusion_3.tpl +0 -1
  199. data/test/blackbox/buffering/input_inclusion_4.exp +0 -0
  200. data/test/blackbox/buffering/input_inclusion_4.tpl +0 -1
  201. data/test/blackbox/buffering/input_inclusion_5.exp +0 -1
  202. data/test/blackbox/buffering/input_inclusion_5.tpl +0 -1
  203. data/test/blackbox/buffering/input_inclusion_6.exp +0 -1
  204. data/test/blackbox/buffering/input_inclusion_6.tpl +0 -1
  205. data/test/blackbox/buffering/input_inclusion_7.exp +0 -0
  206. data/test/blackbox/buffering/input_inclusion_7.tpl +0 -1
  207. data/test/blackbox/buffering/text_1.txt +0 -1
  208. data/test/blackbox/buffering/wlang.txt +0 -1
  209. data/test/blackbox/context/assignment_1.exp +0 -1
  210. data/test/blackbox/context/assignment_1.tpl +0 -1
  211. data/test/blackbox/context/assignment_2.exp +0 -1
  212. data/test/blackbox/context/assignment_2.tpl +0 -1
  213. data/test/blackbox/context/assignment_3.exp +0 -2
  214. data/test/blackbox/context/assignment_3.tpl +0 -2
  215. data/test/blackbox/context/assignment_4.exp +0 -1
  216. data/test/blackbox/context/assignment_4.tpl +0 -1
  217. data/test/blackbox/context/block_assignment_1.exp +0 -1
  218. data/test/blackbox/context/block_assignment_1.tpl +0 -1
  219. data/test/blackbox/context/block_assignment_2.exp +0 -1
  220. data/test/blackbox/context/block_assignment_2.tpl +0 -1
  221. data/test/blackbox/context/modulo_assignment_1.exp +0 -1
  222. data/test/blackbox/context/modulo_assignment_1.tpl +0 -1
  223. data/test/blackbox/context/modulo_assignment_2.exp +0 -1
  224. data/test/blackbox/context/modulo_assignment_2.tpl +0 -1
  225. data/test/blackbox/data_1.rb +0 -1
  226. data/test/blackbox/postblock/hello.exp +0 -1
  227. data/test/blackbox/postblock/hello.pre +0 -1
  228. data/test/blackbox/postblock/hello.tpl +0 -1
  229. data/test/blackbox/postblock/hello_input_inclusion.exp +0 -1
  230. data/test/blackbox/postblock/hello_input_inclusion.tpl +0 -1
  231. data/test/blackbox/postblock/hello_to_authors.exp +0 -1
  232. data/test/blackbox/postblock/hello_to_authors.tpl +0 -1
  233. data/test/blackbox/poststring/hello.exp +0 -1
  234. data/test/blackbox/poststring/hello.tpl +0 -1
  235. data/test/blackbox/test_all.rb +0 -70
  236. data/test/standard_dialects/ruby/data.rb +0 -7
  237. data/test/standard_dialects/ruby/inclusion.exp +0 -6
  238. data/test/standard_dialects/ruby/inclusion.tpl +0 -6
  239. data/test/standard_dialects/test_all.rb +0 -29
  240. data/test/standard_dialects/yaml/assumptions_test.rb +0 -13
  241. data/test/standard_dialects/yaml/data.rb +0 -3
  242. data/test/standard_dialects/yaml/inclusion_1.exp +0 -7
  243. data/test/standard_dialects/yaml/inclusion_1.tpl +0 -2
  244. data/test/standard_dialects/yaml/inclusion_2.exp +0 -5
  245. data/test/standard_dialects/yaml/inclusion_2.tpl +0 -3
  246. data/test/unit/test_all.rb +0 -9
  247. data/test/unit/wlang/anagram_bugs_test.rb +0 -111
  248. data/test/unit/wlang/basic_ruleset_test.rb +0 -52
  249. data/test/unit/wlang/buffering_ruleset_test.rb +0 -102
  250. data/test/unit/wlang/buffering_template1.wtpl +0 -1
  251. data/test/unit/wlang/buffering_template2.wtpl +0 -1
  252. data/test/unit/wlang/buffering_template3.wtpl +0 -1
  253. data/test/unit/wlang/buffering_template4.wtpl +0 -1
  254. data/test/unit/wlang/buffering_template5.wtpl +0 -1
  255. data/test/unit/wlang/context_ruleset_test.rb +0 -32
  256. data/test/unit/wlang/data.rb +0 -3
  257. data/test/unit/wlang/encoder_set_test.rb +0 -42
  258. data/test/unit/wlang/imperative_ruleset_test.rb +0 -107
  259. data/test/unit/wlang/intelligent_buffer_test.rb +0 -194
  260. data/test/unit/wlang/othersymbols_test.rb +0 -16
  261. data/test/unit/wlang/parser_test.rb +0 -88
  262. data/test/unit/wlang/plain_text_dialect_test.rb +0 -21
  263. data/test/unit/wlang/ruby_dialect_test.rb +0 -100
  264. data/test/unit/wlang/ruby_expected.rb +0 -3
  265. data/test/unit/wlang/ruby_template.wrb +0 -3
  266. data/test/unit/wlang/ruleset_utils_test.rb +0 -245
  267. data/test/unit/wlang/specification_examples_test.rb +0 -54
  268. data/test/unit/wlang/test_utils.rb +0 -25
  269. data/test/unit/wlang/wlang_test.rb +0 -80
@@ -0,0 +1,94 @@
1
+ require 'wlang'
2
+ require 'quickl'
3
+ module WLang
4
+ #
5
+ # wlang -- templating engine
6
+ #
7
+ # SYNOPSIS
8
+ # Usage: wlang [options] TEMPLATE
9
+ #
10
+ # OPTIONS:
11
+ # #{summarized_options}
12
+ #
13
+ # DESCRIPTION
14
+ # This command invokes the wlang templating engine on TEMPLATE
15
+ # and flushes the rendering result on standard output.
16
+ #
17
+ class Command < Quickl::Command(__FILE__, __LINE__)
18
+
19
+ options do |opt|
20
+ @output = nil
21
+ opt.on('--output=FILE', 'Render output in FILE') do |file|
22
+ @output = file
23
+ end
24
+ @yaml_front_matter = true
25
+ opt.on("--[no-]yaml-front-matter",
26
+ "Enable/disable YAML front mater (defaults to true)") do |val|
27
+ @yaml_front_matter = val
28
+ end
29
+ @ast = false
30
+ opt.on('--ast', "Debugs the AST") do
31
+ @ast = true
32
+ end
33
+ @compiling_options = {}
34
+ opt.on('--[no-]auto-spacing') do |val|
35
+ @compiling_options[:autospacing] = val
36
+ end
37
+ opt.on_tail("--help", "Show help") do
38
+ raise Quickl::Help
39
+ end
40
+ opt.on_tail("--version", "Show version") do
41
+ raise Quickl::Exit, "#{Quickl.program_name} #{WLang::VERSION} (c) 2009-2012, Bernard Lambeau"
42
+ end
43
+ end
44
+
45
+ def execute(argv)
46
+ install(argv)
47
+
48
+ compiler = @dialect.compiler(@compiling_options)
49
+ if @ast
50
+ require 'awesome_print'
51
+ ap compiler.ast(@template)
52
+ end
53
+
54
+ with_output do |output|
55
+ compiler.compile(@template).render(@context, output)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def install(argv)
62
+ raise Quickl::Help unless argv.size == 1
63
+
64
+ # template file
65
+ unless File.file?(@tpl_file = argv.first)
66
+ raise Quickl::Exit, "No such template #{tpl_file}"
67
+ end
68
+
69
+ # dialect
70
+ require 'wlang/html'
71
+ @dialect = WLang::Html
72
+
73
+ # template and context
74
+ @template = File.read(@tpl_file)
75
+ @context = {}
76
+
77
+ if @yaml_front_matter and
78
+ @template =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
79
+ require 'yaml'
80
+ @context.merge! YAML::load($1)
81
+ @template = $'
82
+ end
83
+ end
84
+
85
+ def with_output(&proc)
86
+ if @output
87
+ File.open(@output, 'w', &proc)
88
+ else
89
+ proc.call($stdout)
90
+ end
91
+ end
92
+
93
+ end # class Command
94
+ end # module WLang
@@ -0,0 +1,78 @@
1
+ require 'wlang/compiler/parser'
2
+ require 'wlang/compiler/filter'
3
+ require 'wlang/compiler/dialect_enforcer'
4
+ require 'wlang/compiler/strconcat_flattener'
5
+ require 'wlang/compiler/proc_call_removal'
6
+ require 'wlang/compiler/autospacing'
7
+ require 'wlang/compiler/to_ruby_abstraction'
8
+ require 'wlang/compiler/static_merger'
9
+ require 'wlang/compiler/to_ruby_code'
10
+ module WLang
11
+ #
12
+ # Provides the wlang compiler which works on the following AST abstractions:
13
+ #
14
+ # - :template, the root element [:template, [:fn, ...]]
15
+ # - :fn, a concrete function [:fn, code]
16
+ # - :wlang, a high-order function [:wlang, symbols, [:fn, ..], [:fn, ...], ...]
17
+ # - :strconcat, concatenation [:strconcat, [...], [...], [...]]
18
+ # - :modulo, modulation [:modulo, dialect, [:fn, ...]]
19
+ # - :static, constant text [:static, "..."]
20
+ #
21
+ class Compiler
22
+
23
+ attr_reader :dialect
24
+
25
+ def initialize(dialect)
26
+ @dialect = dialect
27
+ end
28
+
29
+ def options
30
+ dialect.options
31
+ end
32
+
33
+ def compile(source)
34
+ case source
35
+ when Template
36
+ source
37
+ when Proc
38
+ Template.new(@dialect, source)
39
+ else
40
+ code = to_ruby_code(source)
41
+ proc = eval(code, TOPLEVEL_BINDING)
42
+ Template.new(@dialect, proc)
43
+ end
44
+ end
45
+
46
+ def to_ruby_code(source)
47
+ engine.call(source)
48
+ end
49
+
50
+ def ast(source)
51
+ parser.new.call(source)
52
+ end
53
+
54
+ def parser
55
+ Class.new(Temple::Engine).tap{|c|
56
+ c.use Parser
57
+ c.use DialectEnforcer, :dialect => @dialect
58
+ c.use Autospacing if options[:autospacing]
59
+ c.use StrconcatFlattener
60
+ c.use StaticMerger
61
+ }
62
+ end
63
+
64
+ def engine(gencode = true)
65
+ Class.new(Temple::Engine).tap{|c|
66
+ c.use Parser
67
+ c.use DialectEnforcer, :dialect => @dialect
68
+ c.use Autospacing if options[:autospacing]
69
+ c.use StrconcatFlattener
70
+ c.use StaticMerger
71
+ c.use ProcCallRemoval
72
+ c.use ToRubyAbstraction
73
+ c.use ToRubyCode if gencode
74
+ }.new
75
+ end
76
+
77
+ end # class Compiler
78
+ end # module WLang
@@ -0,0 +1,60 @@
1
+ module WLang
2
+ class Compiler
3
+ class Autospacing < Filter
4
+
5
+ def on_strconcat(*exps)
6
+ optimized = []
7
+ exps.each_with_index do |exp,i|
8
+ optimized[i] = call(exp)
9
+ if exp.first == :wlang and multiline?(exp) and i != 0
10
+ optimized[i-1] = RightStrip.new.call(optimized[i-1])
11
+ end
12
+ end
13
+ [:strconcat] + optimized
14
+ end
15
+
16
+ def on_wlang(symbols, *fns)
17
+ fns.inject [:wlang, symbols] do |rw,fn|
18
+ fn = Unindent.new.call(fn)
19
+ fn = RightStrip.new.call(fn)
20
+ rw << call(fn)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def multiline?(who)
27
+ case who.first
28
+ when :static
29
+ who.last =~ /\n/
30
+ when :wlang, :modulo
31
+ who[2..-1].any?{|s| s && multiline?(s)}
32
+ else
33
+ who[1..-1].any?{|s| s && multiline?(s)}
34
+ end
35
+ end
36
+
37
+ class RightStrip < Filter
38
+
39
+ def on_strconcat(*exps)
40
+ exps[-1] = call(exps[-1])
41
+ [:strconcat] + exps
42
+ end
43
+
44
+ def on_static(text)
45
+ [:static, text.gsub(/\s+\Z/m, '')]
46
+ end
47
+
48
+ end # class RightStrip
49
+
50
+ class Unindent < Filter
51
+
52
+ def on_static(text)
53
+ [:static, text.gsub(/^ /m, '')]
54
+ end
55
+
56
+ end # class Unindent
57
+
58
+ end # class Autospacing
59
+ end # class Compiler
60
+ end # module WLang
@@ -0,0 +1,91 @@
1
+ module WLang
2
+ class Compiler
3
+ class DialectEnforcer < Filter
4
+
5
+ def dialect; options[:dialect]; end
6
+
7
+ def on_wlang(symbols, *fns)
8
+ extra, meth = find_dispatching_method(symbols, :unbound_method)
9
+ if meth
10
+ argsize, arity = fns.size, meth.arity - 1
11
+ if extra.size > 0
12
+ rewrite_extra_symbols(extra, symbols[extra.length..-1], fns)
13
+ elsif argsize > arity
14
+ rewrite_trailing_fns(symbols, fns[0...arity], fns[arity..-1])
15
+ elsif argsize < arity
16
+ rewrite_missing_fns(symbols, fns, arity - argsize)
17
+ else
18
+ enforce_sub_dialects(symbols, fns)
19
+ end
20
+ else
21
+ rewrite_unknown_tag(symbols, fns)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def enforce_sub_dialects(symbols, fns)
28
+ ds = dialect.dialects_for(symbols) || []
29
+ fns.zip(ds).inject [:wlang, symbols] do |rw, (fn, d)|
30
+ if d
31
+ enforcer = DialectEnforcer.new(:dialect => d.factor)
32
+ rw << [:modulo, d, enforcer.call(fn)]
33
+ else
34
+ rw << call(fn)
35
+ end
36
+ end
37
+ end
38
+
39
+ def rewrite_missing_fns(symbols, fns, count)
40
+ count.times do
41
+ fns << [:arg, nil]
42
+ end
43
+ call([:wlang, symbols] + fns)
44
+ end
45
+
46
+ def rewrite_trailing_fns(symbols, fns, trailing)
47
+ wlanged = call([:wlang, symbols] + fns)
48
+ trailing.inject [:strconcat, wlanged] do |rw,fn|
49
+ rw << [:static, '{']
50
+ rw << call(fn.last)
51
+ rw << [:static, '}']
52
+ end
53
+ end
54
+
55
+ def rewrite_extra_symbols(extra, symbols, fns)
56
+ wlang = fns.inject [:wlang, symbols] do |rw,fn|
57
+ rw << fn
58
+ end
59
+ [:strconcat, [:static, extra], call(wlang)]
60
+ end
61
+
62
+ def rewrite_unknown_tag(symbols, fns)
63
+ start, stop = dialect.braces
64
+ from = [:strconcat, [:static, symbols]]
65
+ fns.inject(from) do |rw, fn|
66
+ rw << [:static, start]
67
+ rw << call(fn.last)
68
+ rw << [:static, stop]
69
+ end
70
+ end
71
+
72
+ def find_dispatching_method(symbols, kind = :name)
73
+ extra, symbols, found = [], symbols.chars.to_a, nil
74
+ dialect.tap do |d|
75
+ begin
76
+ meth = Dialect.tag_dispatching_name(symbols)
77
+ if d.respond_to?(meth)
78
+ found = d.class.instance_method(meth)
79
+ break
80
+ else
81
+ extra << symbols.shift
82
+ end
83
+ end until symbols.empty?
84
+ end
85
+ found = found.name.to_sym if found && kind == :name
86
+ [extra.join, found]
87
+ end
88
+
89
+ end # class DialectEnforcer
90
+ end # class Compiler
91
+ end # module WLang
@@ -0,0 +1,32 @@
1
+ module WLang
2
+ class Compiler
3
+ class Filter < Temple::Filter
4
+
5
+ module ClassMethods
6
+
7
+ def recurse_on(*kinds)
8
+ kinds.each do |kind|
9
+ define_method(:"on_#{kind}") do |*args|
10
+ recurse(kind, *args)
11
+ end
12
+ end
13
+ end
14
+
15
+ end
16
+ extend ClassMethods
17
+
18
+ module InstanceMethods
19
+
20
+ def recurse(kind, *args)
21
+ args.inject [kind] do |rw,arg|
22
+ rw << (arg.is_a?(Array) ? call(arg) : arg)
23
+ end
24
+ end
25
+
26
+ end
27
+ include InstanceMethods
28
+
29
+ recurse_on :template, :fn, :wlang, :strconcat, :modulo, :static
30
+ end # class Filter
31
+ end # class Compiler
32
+ end # module WLang
@@ -0,0 +1,67 @@
1
+ grammar WLang::Grammar
2
+
3
+ rule template
4
+ (strconcat !.){
5
+ [:template, [:fn, strconcat.value]]
6
+ }
7
+ end
8
+
9
+ rule strconcat
10
+ (non_static | static)* {
11
+ if matches.size == 1
12
+ matches.first.value
13
+ else
14
+ [:strconcat] + matches.map(&:value)
15
+ end
16
+ }
17
+ end
18
+
19
+ rule static
20
+ (!stop_char .)+ {
21
+ [:static, to_s]
22
+ }
23
+ end
24
+
25
+ rule non_static
26
+ block | wlang
27
+ end
28
+
29
+ rule block
30
+ (fn_start strconcat fn_stop){
31
+ [:static, to_s]
32
+ }
33
+ end
34
+
35
+ rule wlang
36
+ (symbols functions){
37
+ [:wlang, symbols.to_s] + functions.value
38
+ }
39
+ end
40
+
41
+ rule functions
42
+ function+ { matches.map{|fn| [:fn, fn.value]} }
43
+ end
44
+
45
+ rule function
46
+ (fn_start strconcat fn_stop){
47
+ strconcat.value
48
+ }
49
+ end
50
+
51
+ rule stop_char
52
+ fn_start | fn_stop | (symbols fn_start)
53
+ end
54
+
55
+ rule symbols
56
+ /[!\^%"\$&'\*\+\?@~\#,\-\.\/:;=<>\|_]+/
57
+ end
58
+
59
+ rule fn_start
60
+ '{'
61
+ end
62
+
63
+ rule fn_stop
64
+ '}'
65
+ end
66
+
67
+ end
@@ -0,0 +1,26 @@
1
+ module WLang
2
+ Citrus.load(File.expand_path('../grammar', __FILE__))
3
+ class Parser
4
+
5
+ def initialize(options = {})
6
+ end
7
+
8
+ def call(input)
9
+ return input if input.is_a?(Array)
10
+ parser.parse(parsing_source(input)).value
11
+ end
12
+
13
+ private
14
+
15
+ def parser
16
+ WLang::Grammar
17
+ end
18
+
19
+ def parsing_source(input)
20
+ input = File.read(input.to_path) if input.respond_to?(:to_path)
21
+ input = input.to_str if input.respond_to?(:to_str)
22
+ input
23
+ end
24
+
25
+ end # class Engine
26
+ end # module WLang