wlang 0.10.2 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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