emerald-lang 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +18 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/emerald +7 -0
- data/bin/setup +7 -0
- data/circle.yml +13 -0
- data/config/pre_commit.yml +5 -0
- data/emerald-logo.png +0 -0
- data/emerald.gemspec +33 -0
- data/lib/emerald.rb +75 -0
- data/lib/emerald/grammar.rb +90 -0
- data/lib/emerald/grammar/emerald.tt +93 -0
- data/lib/emerald/grammar/scopes.tt +48 -0
- data/lib/emerald/grammar/tokens.tt +57 -0
- data/lib/emerald/grammar/variables.tt +10 -0
- data/lib/emerald/index.emr +33 -0
- data/lib/emerald/nodes/attribute_list.rb +13 -0
- data/lib/emerald/nodes/attributes.rb +16 -0
- data/lib/emerald/nodes/base_scope_fn.rb +11 -0
- data/lib/emerald/nodes/binary_expr.rb +17 -0
- data/lib/emerald/nodes/boolean_expr.rb +11 -0
- data/lib/emerald/nodes/comment.rb +12 -0
- data/lib/emerald/nodes/each.rb +40 -0
- data/lib/emerald/nodes/given.rb +16 -0
- data/lib/emerald/nodes/line.rb +13 -0
- data/lib/emerald/nodes/nested.rb +17 -0
- data/lib/emerald/nodes/node.rb +11 -0
- data/lib/emerald/nodes/pair_list.rb +23 -0
- data/lib/emerald/nodes/root.rb +14 -0
- data/lib/emerald/nodes/scope.rb +12 -0
- data/lib/emerald/nodes/scope_fn.rb +12 -0
- data/lib/emerald/nodes/tag_statement.rb +78 -0
- data/lib/emerald/nodes/text_literal.rb +26 -0
- data/lib/emerald/nodes/unary_expr.rb +16 -0
- data/lib/emerald/nodes/unless.rb +16 -0
- data/lib/emerald/nodes/value_list.rb +18 -0
- data/lib/emerald/nodes/variable.rb +14 -0
- data/lib/emerald/nodes/variable_name.rb +21 -0
- data/lib/emerald/nodes/with.rb +14 -0
- data/lib/emerald/preprocessor.rb +145 -0
- data/lib/emerald/version.rb +3 -0
- data/sample.emr +45 -0
- metadata +245 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -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
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -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
|
data/bin/emerald
ADDED
data/bin/setup
ADDED
data/circle.yml
ADDED
data/emerald-logo.png
ADDED
Binary file
|
data/emerald.gemspec
ADDED
@@ -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
|
data/lib/emerald.rb
ADDED
@@ -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
|