emerald-lang 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +17 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +18 -0
  9. data/Rakefile +12 -0
  10. data/bin/console +14 -0
  11. data/bin/emerald +7 -0
  12. data/bin/setup +7 -0
  13. data/circle.yml +13 -0
  14. data/config/pre_commit.yml +5 -0
  15. data/emerald-logo.png +0 -0
  16. data/emerald.gemspec +33 -0
  17. data/lib/emerald.rb +75 -0
  18. data/lib/emerald/grammar.rb +90 -0
  19. data/lib/emerald/grammar/emerald.tt +93 -0
  20. data/lib/emerald/grammar/scopes.tt +48 -0
  21. data/lib/emerald/grammar/tokens.tt +57 -0
  22. data/lib/emerald/grammar/variables.tt +10 -0
  23. data/lib/emerald/index.emr +33 -0
  24. data/lib/emerald/nodes/attribute_list.rb +13 -0
  25. data/lib/emerald/nodes/attributes.rb +16 -0
  26. data/lib/emerald/nodes/base_scope_fn.rb +11 -0
  27. data/lib/emerald/nodes/binary_expr.rb +17 -0
  28. data/lib/emerald/nodes/boolean_expr.rb +11 -0
  29. data/lib/emerald/nodes/comment.rb +12 -0
  30. data/lib/emerald/nodes/each.rb +40 -0
  31. data/lib/emerald/nodes/given.rb +16 -0
  32. data/lib/emerald/nodes/line.rb +13 -0
  33. data/lib/emerald/nodes/nested.rb +17 -0
  34. data/lib/emerald/nodes/node.rb +11 -0
  35. data/lib/emerald/nodes/pair_list.rb +23 -0
  36. data/lib/emerald/nodes/root.rb +14 -0
  37. data/lib/emerald/nodes/scope.rb +12 -0
  38. data/lib/emerald/nodes/scope_fn.rb +12 -0
  39. data/lib/emerald/nodes/tag_statement.rb +78 -0
  40. data/lib/emerald/nodes/text_literal.rb +26 -0
  41. data/lib/emerald/nodes/unary_expr.rb +16 -0
  42. data/lib/emerald/nodes/unless.rb +16 -0
  43. data/lib/emerald/nodes/value_list.rb +18 -0
  44. data/lib/emerald/nodes/variable.rb +14 -0
  45. data/lib/emerald/nodes/variable_name.rb +21 -0
  46. data/lib/emerald/nodes/with.rb +14 -0
  47. data/lib/emerald/preprocessor.rb +145 -0
  48. data/lib/emerald/version.rb +3 -0
  49. data/sample.emr +45 -0
  50. metadata +245 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b98b2000688c656f6b8d50dc7ca337140c0ce108
4
+ data.tar.gz: 56ed522869ab837b945e2859bdfbeedef6f5d1c9
5
+ SHA512:
6
+ metadata.gz: 4f86668e7bdcf4cb162b4b199fb0bd8881e11c675e014df62cbb119f06f25a963a024b8683fa0f8a064fb6ec6f3fa630c43098299fbf9e5768a6ac6e0e021c28
7
+ data.tar.gz: a11b96888f15fb9017427ecffef1a232cce785ad066c7e2c11faf42ce280d23a59d4c4e07c30edce6d2728c51e84f1c765c311d066125ab75b1e7d029ca29729
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ bin/pre-commit
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,17 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+
4
+ Style/SpaceInsideHashLiteralBraces:
5
+ EnforcedStyle: no_space
6
+
7
+ Metrics/AbcSize:
8
+ Enabled: false
9
+
10
+ Metrics/MethodLength:
11
+ Max: 30
12
+
13
+ Style/DoubleNegation:
14
+ Enabled: false
15
+
16
+ Style/WordArray:
17
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.3.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in emerald.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Andrew McBurney, Dave Pagurek, Yu Chen Hu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ <img src='emerald-logo.png' alt='Drawing' width='600px' />
2
+ - A language agnostic templating engine designed with event driven applications in mind.
3
+
4
+ # Usage
5
+ ```
6
+ bin/emerald process some_html_file --beautify
7
+ ```
8
+
9
+ # Setup
10
+ ```
11
+ bundle install
12
+ bundle exec rake setup
13
+ ```
14
+
15
+ # Running tests
16
+ ```
17
+ bundle exec rake test
18
+ ```
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'pre-commit'
4
+
5
+ RSpec::Core::RakeTask.new(:test)
6
+
7
+ task :setup do
8
+ sh 'pre-commit install'
9
+ sh 'git config pre-commit.checks "[rubocop]"'
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "emerald"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'emerald'
6
+
7
+ Emerald::CLI.start(ARGV)
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,13 @@
1
+ machine:
2
+ ruby:
3
+ version:
4
+ 2.3.2
5
+
6
+ dependencies:
7
+ override:
8
+ - bundle install:
9
+ timeout: 240
10
+
11
+ test:
12
+ override:
13
+ - bundle exec rake test
@@ -0,0 +1,5 @@
1
+ ---
2
+ :checks_add:
3
+ - :rubocop
4
+ :checks_remove:
5
+ - :rails
Binary file
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'emerald/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'emerald-lang'
8
+ spec.version = Emerald::VERSION
9
+ spec.authors = ['Andrew McBurney', 'Dave Pagurek', 'Yu Chen Hu']
10
+ spec.email = ['andrewrobertmcburney@gmail.com', 'davepagurek@gmail.com', 'me@yuchenhou.com']
11
+
12
+ spec.summary = 'A language agnostic templating engine designed with event driven applications in mind.'
13
+ spec.description = 'A language agnostic templating engine designed with event driven applications in mind.' # TODO: make better description
14
+ spec.homepage = 'https://github.com/emerald-lang/emerald' # TODO: replace with website once created
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'bin'
19
+ spec.executables = ['emerald']
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.10'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'test-unit'
26
+ spec.add_development_dependency 'rubocop'
27
+ spec.add_development_dependency 'pre-commit'
28
+
29
+ spec.add_runtime_dependency 'htmlentities'
30
+ spec.add_runtime_dependency 'treetop'
31
+ spec.add_runtime_dependency 'thor'
32
+ spec.add_runtime_dependency 'htmlbeautifier', '~> 1.1', '>= 1.1.1'
33
+ end
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Emerald, the language agnostic templating engine.
6
+ # Copyright 2016, Emerald Language (MIT)
7
+ #
8
+ require 'emerald/version'
9
+
10
+ require 'json'
11
+ require 'thor'
12
+ require 'htmlbeautifier'
13
+
14
+ require_relative 'emerald/grammar'
15
+ require_relative 'emerald/preprocessor'
16
+
17
+ # Parses a context free grammar from the preprocessed emerald and generates
18
+ # html associated with corresponding abstract syntax tree.
19
+ module Emerald
20
+ # The Emerald CLI
21
+ class CLI < Thor
22
+ class_option :beautify, :type => :boolean, :aliases => 'b'
23
+
24
+ def self.exit_on_failure?
25
+ true
26
+ end
27
+
28
+ # Main emerald option, processes the emerald file, generates an abstract
29
+ # syntax tree based on the output from the preprocessing.
30
+ desc 'process', 'Process a file or folder (recursively) and converts it to emerald.'
31
+ option :output, aliases: 'o'
32
+ def process(file_name, context_file_name = nil)
33
+ begin
34
+ output_name = options[:output] || file_name
35
+ context =
36
+ if context_file_name
37
+ JSON.parse(IO.read(context_file_name))
38
+ else
39
+ {}
40
+ end
41
+
42
+ input = IO.read(file_name)
43
+
44
+ Emerald.write_html(
45
+ Emerald.convert(input, context),
46
+ output_name,
47
+ options['beautify']
48
+ )
49
+ rescue Grammar::PreProcessorError, Grammar::ParserError => e
50
+ raise Thor::Error, e.message
51
+ end
52
+ end
53
+ end
54
+
55
+ def self.convert(input, context = {})
56
+ preprocessed_emerald, source_map = PreProcessor.new.process_emerald(input)
57
+ abstract_syntax_tree = Grammar.parse_grammar(
58
+ preprocessed_emerald,
59
+ input,
60
+ source_map
61
+ )
62
+
63
+ return abstract_syntax_tree.to_html(context)
64
+ end
65
+
66
+ # Write html to file and beautify it if the beautify global option is set to
67
+ # true.
68
+ def self.write_html(html_output, file_name, beautify)
69
+ File.open(file_name + '.html', 'w') do |emerald_file|
70
+ html_output = HtmlBeautifier.beautify(html_output) if beautify
71
+ emerald_file.write(html_output)
72
+ end
73
+ puts "Wrote #{file_name + '.html'}"
74
+ end
75
+ end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'polyglot'
5
+ require 'treetop'
6
+
7
+ # Require all treetop nodes for grammar
8
+ Dir[File.dirname(__FILE__) + '/nodes/*.rb'].each { |f| require f }
9
+
10
+ Treetop.load __dir__ + '/grammar/tokens'
11
+ Treetop.load __dir__ + '/grammar/variables'
12
+ Treetop.load __dir__ + '/grammar/scopes'
13
+ Treetop.load __dir__ + '/grammar/emerald'
14
+
15
+ #
16
+ # Interface which interacts with emerald context free grammar. Parses the
17
+ # preprocessed Emerald and prints out success if the parser was successful and
18
+ # failure if there was an error when parsing. Returns an abstract syntax tree.
19
+ #
20
+ module Grammar
21
+ # When the parser fails on a line from user input
22
+ class ParserError < StandardError
23
+ LINES_BEFORE = 3
24
+ LINES_AFTER = 1
25
+
26
+ def initialize(line_number, reason, source)
27
+ @line_number = line_number
28
+ @reason = reason
29
+ @source = source
30
+ end
31
+
32
+ def message
33
+ messages = []
34
+ if match = @reason.match(/(Expected .+?) at line/)
35
+ messages << match[1]
36
+ else
37
+ messages << @reason
38
+ end
39
+
40
+ lines = @source.split(/\n/)
41
+ LINES_BEFORE.downto(1).each do |i|
42
+ messages << ' ' + lines[@line_number - i - 1] if lines[@line_number - i - 1]
43
+ end
44
+ messages << '>>> ' + lines[@line_number - 1]
45
+ 1.upto(LINES_AFTER).each do |i|
46
+ messages << ' ' + lines[@line_number + i - 1] if lines[@line_number + i - 1]
47
+ end
48
+
49
+ messages.join("\n")
50
+ end
51
+ end
52
+
53
+ # When the parser fails on a line added only in preprocessing
54
+ class PreProcessorError < ParserError
55
+ def say
56
+ messages = []
57
+ messages << "Error parsing in pre-processed Emerald. This is likely a bug."
58
+ messages << @reason
59
+ messages.concat(@source.lines.with_index { |line, i| puts "#{i + 1} #{line}" })
60
+
61
+ messages.join("\n")
62
+ end
63
+ end
64
+
65
+ @parser = EmeraldParser.new
66
+
67
+ # Parse the preprocessed emerald text and print failure if it fails the
68
+ # parsing stage
69
+ def self.parse_grammar(text, original, source_map)
70
+ parsed = @parser.parse(text)
71
+
72
+ if parsed.nil?
73
+ source_line = source_map[@parser.failure_line][:source_line]
74
+ if source_line.nil?
75
+ raise PreProcessorError.new(
76
+ @parser.failure_line,
77
+ @parser.failure_reason,
78
+ text
79
+ )
80
+ end
81
+ raise ParserError.new(
82
+ source_line,
83
+ @parser.failure_reason,
84
+ original
85
+ )
86
+ end
87
+
88
+ parsed
89
+ end
90
+ end
@@ -0,0 +1,93 @@
1
+ #
2
+ # Context free grammar for the Emerald language.
3
+ # Emerald: a preprocessor for html5.
4
+ #
5
+ grammar Emerald
6
+ include Tokens
7
+ include Scopes
8
+ include Variables
9
+
10
+ rule main
11
+ (scope / pair_list / value_list / nested / line / comment)+ <Root>
12
+ end
13
+
14
+ rule nested
15
+ tag_statement newline lbrace newline main rbrace newline <Nested>
16
+ end
17
+
18
+ rule scope
19
+ fn:scope_fn lbrace newline body:main rbrace newline <Scope>
20
+ end
21
+
22
+ rule line
23
+ (tag_statement / comment) newline <Line>
24
+ end
25
+
26
+ rule value_list
27
+ keyword:special_keyword newline lbrace newline
28
+ list_items:(literal:inline_literal_string newline)+
29
+ rbrace newline <ValueList>
30
+ end
31
+
32
+ rule pair_list
33
+ keyword:base_keyword newline lbrace newline
34
+ list_items:(pairs:(attr:attr space+ literal:inline_literal_string space*)+ newline)+
35
+ rbrace newline <PairList>
36
+ end
37
+
38
+ rule comment
39
+ space* '*' space* text_content <Comment>
40
+ end
41
+
42
+ rule text_content
43
+ multiline_literal / multiline_templateless_literal / inline_literal
44
+ end
45
+
46
+ rule multiline_literal
47
+ "->" space* newline
48
+ body:(variable / escaped / !'$' .)*
49
+ "$" <TextLiteral>
50
+ end
51
+
52
+ rule multiline_templateless_literal
53
+ ("=>" / "~>") space* newline
54
+ body:(escaped / !'$' .)*
55
+ "$" <TextLiteral>
56
+ end
57
+
58
+ rule inline_literal
59
+ body:( variable / escaped / !lparen !newline . )* <TextLiteral>
60
+ end
61
+
62
+ rule inline_literal_string
63
+ '"' body:( variable / escaped / !'"' . )* '"' <TextLiteral>
64
+ end
65
+
66
+ rule escaped
67
+ "\\" .
68
+ end
69
+
70
+ rule tag_statement
71
+ tag identifier:id_name? classes:class_name* space* body:text_content? attributes:attr_list? <TagStatement>
72
+ end
73
+
74
+ rule id_name
75
+ '#' name:([a-zA-Z_\-]+)
76
+ end
77
+
78
+ rule class_name
79
+ '.' name:([a-zA-Z_\-]+)
80
+ end
81
+
82
+ rule attr_list
83
+ lparen newline lbrace newline attributes rbrace newline rparen <AttributeList>
84
+ end
85
+
86
+ rule attributes
87
+ attribute* <Attributes>
88
+ end
89
+
90
+ rule attribute
91
+ attr space* inline_literal_string newline
92
+ end
93
+ end