c66-copper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +5 -0
  3. data/bin/console +14 -0
  4. data/bin/copper +96 -0
  5. data/bin/setup +8 -0
  6. data/lib/copper/action.rb +9 -0
  7. data/lib/copper/attribute.rb +30 -0
  8. data/lib/copper/attribute_params.rb +9 -0
  9. data/lib/copper/attributes.rb +21 -0
  10. data/lib/copper/attributes_right_associated.rb +11 -0
  11. data/lib/copper/boolean.rb +9 -0
  12. data/lib/copper/comparison.rb +58 -0
  13. data/lib/copper/compop.rb +8 -0
  14. data/lib/copper/copper.rb +32 -0
  15. data/lib/copper/copper_node.rb +16 -0
  16. data/lib/copper/data_types/array.rb +61 -0
  17. data/lib/copper/data_types/data_type.rb +54 -0
  18. data/lib/copper/data_types/ip_addr.rb +82 -0
  19. data/lib/copper/data_types/range.rb +17 -0
  20. data/lib/copper/data_types/semver.rb +45 -0
  21. data/lib/copper/data_types/string.rb +23 -0
  22. data/lib/copper/error.rb +5 -0
  23. data/lib/copper/expression.rb +8 -0
  24. data/lib/copper/expression_utils.rb +13 -0
  25. data/lib/copper/functions/fetch.rb +27 -0
  26. data/lib/copper/functions/ip_address.rb +18 -0
  27. data/lib/copper/grammar/copper.treetop +161 -0
  28. data/lib/copper/identifier.rb +9 -0
  29. data/lib/copper/loader.rb +13 -0
  30. data/lib/copper/logic.rb +14 -0
  31. data/lib/copper/logic_op.rb +7 -0
  32. data/lib/copper/logic_right_associated.rb +16 -0
  33. data/lib/copper/number.rb +10 -0
  34. data/lib/copper/param.rb +13 -0
  35. data/lib/copper/param_right_associated.rb +10 -0
  36. data/lib/copper/parser.rb +42 -0
  37. data/lib/copper/range.rb +15 -0
  38. data/lib/copper/root.rb +13 -0
  39. data/lib/copper/rule_definition.rb +21 -0
  40. data/lib/copper/set.rb +11 -0
  41. data/lib/copper/single_var_definition.rb +20 -0
  42. data/lib/copper/string.rb +17 -0
  43. data/lib/copper/var_definition.rb +11 -0
  44. data/lib/copper/variable.rb +9 -0
  45. data/lib/copper/variable_identifier.rb +15 -0
  46. data/lib/copper/version.rb +5 -0
  47. data/lib/copper.rb +5 -0
  48. metadata +247 -0
@@ -0,0 +1,27 @@
1
+ require 'jsonpath'
2
+
3
+ module Copper
4
+ module Functions
5
+ class Fetch < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ key = elements[0].value(vars)
11
+ context = vars[:context]
12
+
13
+ begin
14
+ path = JsonPath.new(key)
15
+ result = path.on(context)
16
+ rescue ArgumentError => exc
17
+ raise ParseError, "JSONPath error #{key}: #{exc.message}"
18
+ rescue NoMethodError => exc
19
+ raise ParseError, "JSONPath error #{key}. Invalid JSONPath"
20
+ end
21
+
22
+ return handle_attributes(result, vars)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ require 'ipaddress'
2
+
3
+ module Copper
4
+ module Functions
5
+ class IPAddress < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ ipaddress = elements[0].value(vars)
11
+ result = ::IPAddress.parse(ipaddress)
12
+
13
+ return handle_attributes(result, vars)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,161 @@
1
+ grammar Copper
2
+
3
+ rule root
4
+ (var_definition / rule_definition / comment / comment_block)+ <Root>
5
+ end
6
+
7
+ rule comment
8
+ s '//' (![\n\r] .)* [\n\r]
9
+ end
10
+
11
+ rule comment_block
12
+ s '/*' (!'*/' .)* '*/' s
13
+ end
14
+
15
+ rule rule_definition
16
+ s 'rule' s identifier s action s '{' sn
17
+ logic sn
18
+ '}' sn
19
+ <RuleDefinition>
20
+ end
21
+
22
+ rule var_definition
23
+ s 'var' s single_var_definition
24
+ <VarDefinition>
25
+ end
26
+
27
+ rule single_var_definition
28
+ s identifier s '=' s expression sn <SingleVarDefinition>
29
+ end
30
+
31
+ rule logic
32
+ s comparison s (logic_right_associated)? sn <Logic>
33
+ end
34
+
35
+ rule range
36
+ s '(' s expression s '..' s expression s ')' (attributes)? <Range>
37
+ end
38
+
39
+ rule expression
40
+ s (string / number / boolean / func / variable / set / range) <Expression>
41
+ end
42
+
43
+ rule logic_right_associated
44
+ logic_op sn logic <LogicRightAssociated>
45
+ end
46
+
47
+ rule action
48
+ 'ensure' <Action>
49
+ / 'warn' <Action>
50
+ end
51
+
52
+ rule logic_op
53
+ 'and' <LogicOp>
54
+ / '&' <LogicOp>
55
+ / '&&' <LogicOp>
56
+ / 'or' <LogicOp>
57
+ / '|' <LogicOp>
58
+ / '||' <LogicOp>
59
+ / '->' <CompOp>
60
+ end
61
+
62
+ rule comparison
63
+ s expression s comp_op s expression <Comparison>
64
+ / s boolean <Boolean>
65
+ end
66
+
67
+ rule func
68
+ (fetch_func / func_ipaddress)
69
+ end
70
+
71
+ rule fetch_func
72
+ 'fetch' s '(' s (string / variable) s ')' (attributes)? <Functions::Fetch>
73
+ end
74
+
75
+ rule func_ipaddress
76
+ 'ipaddress' s '(' (string / variable) s ')' (attributes)? <Functions::IPAddress>
77
+ end
78
+
79
+ rule attributes
80
+ sn '.' attribute (attributes_right_associated)? <Attributes>
81
+ end
82
+
83
+ rule attributes_right_associated
84
+ (attributes) <AttributesRightAssociated>
85
+ end
86
+
87
+ rule attribute
88
+ identifier attribute_params? <Attribute>
89
+ end
90
+
91
+ rule params
92
+ s expression s (param_right_associated)? <Param>
93
+ end
94
+
95
+ rule param_right_associated
96
+ ',' s params <ParamRightAssociated>
97
+ end
98
+
99
+ rule attribute_params
100
+ s '(' s (params) s ')' <AttributeParams>
101
+ end
102
+
103
+ rule set
104
+ s '[' (params) s ']' (attributes)? <Set>
105
+ end
106
+
107
+ rule variable_identifier
108
+ [a-zA-Z] [a-zA-Z0-9_]* <VariableIdentifier>
109
+ end
110
+
111
+ rule variable
112
+ variable_identifier (attributes)? <Variable>
113
+ end
114
+
115
+ rule identifier
116
+ [a-zA-Z] [a-zA-Z0-9_]* <Identifier>
117
+ end
118
+
119
+ rule number
120
+ [0-9]+ <Number>
121
+ end
122
+
123
+ rule comp_op
124
+ '<=' <CompOp>
125
+ / '>=' <CompOp>
126
+ / '<' <CompOp>
127
+ / '>' <CompOp>
128
+ / '==' <CompOp>
129
+ / '=' <CompOp>
130
+ / '!=' <CompOp>
131
+ / 'in' <CompOp>
132
+ / '->' <CompOp>
133
+ end
134
+
135
+ rule boolean
136
+ 'true' <Boolean>
137
+ / 'false' <Boolean>
138
+ / 'console' <Boolean>
139
+ end
140
+
141
+ rule string
142
+ '"' string_content '"' (attributes)? <String>
143
+ end
144
+
145
+ rule string_content
146
+ ([^"\\] / "\\" . )* <StringContent>
147
+ end
148
+
149
+ rule sn
150
+ s '//' (![\n\r] .)* [\n\r] / s / s [\n\r] / [\n\r]
151
+ end
152
+
153
+ rule s
154
+ [\s\t]*
155
+ end
156
+
157
+ rule S
158
+ [\s\t]+
159
+ end
160
+
161
+ end
@@ -0,0 +1,9 @@
1
+ module Copper
2
+ # Node class for an identifier
3
+ class Identifier < CopperNode
4
+
5
+ def value(vars = {})
6
+ return self.text_value.to_sym
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ require 'treetop'
2
+
3
+ # Load the parser from the Treetop grammar.
4
+ Treetop.load(File.join(__dir__, 'grammar', 'copper.treetop'))
5
+
6
+ require File.join(__dir__, 'data_types', 'data_type')
7
+ # Load custom Copper syntax node.
8
+ require File.join(__dir__, 'copper_node')
9
+
10
+ require File.join(__dir__, 'expression_utils')
11
+
12
+ # Load other Copper classes.
13
+ Dir.glob File.join(__dir__, '**', '*.rb'), &method(:require)
@@ -0,0 +1,14 @@
1
+ module Copper
2
+ class Logic < CopperNode
3
+ def value(vars = {})
4
+ if elements[1].nil?
5
+ # no right association
6
+ return elements[0].value(vars)
7
+ else
8
+ # has right association
9
+ return elements[1].value(vars)
10
+ end
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,7 @@
1
+ module Copper
2
+ class LogicOp < CopperNode
3
+ def value(vars = {})
4
+ return text_value
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module Copper
2
+ class LogicRightAssociated < CopperNode
3
+ def value(vars = {})
4
+ rhs = self.parent.elements[0].value(vars)
5
+ op = self.elements[0].value(vars)
6
+ lhs = self.elements[1].value(vars)
7
+
8
+ case op
9
+ when 'and', '&', '&&'
10
+ return (lhs and rhs)
11
+ when 'or', '|', '||'
12
+ return (lhs or rhs)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module Copper
2
+ # Node class for a simple number.
3
+ class Number < CopperNode
4
+
5
+ def value(vars = {})
6
+ return text_value.to_i
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Copper
2
+ class Param < CopperNode
3
+ def value(vars = {})
4
+ if elements[1].nil?
5
+ # no right association
6
+ return elements[0].value(vars)
7
+ else
8
+ # has right association
9
+ return elements[1].value(vars)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Copper
2
+ class ParamRightAssociated < CopperNode
3
+ def value(vars = {})
4
+ rhs = self.parent.elements[0].value(vars)
5
+ lhs = self.elements[0].value(vars)
6
+
7
+ return ([rhs] + [lhs]).flatten
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module Copper
2
+ class Parser
3
+ def initialize
4
+ @parser = CopperParser.new
5
+ end
6
+
7
+ def parse(content)
8
+ root_node = @parser.parse(content)
9
+
10
+ # Raise any errors.
11
+ unless root_node
12
+ @parser.failure_reason =~ /^(Expected .+) after/m
13
+ if $1.nil?
14
+ puts "#{@parser.failure_reason}"
15
+ else
16
+ puts "#{$1.gsub("\n", '$NEWLINE')}:"
17
+ end
18
+ puts content.lines.to_a[@parser.failure_line - 1]
19
+ puts "#{'~' * (@parser.failure_column - 1)}^"
20
+ return nil
21
+ end
22
+
23
+ puts root_node.inspect if $parser_debug
24
+
25
+ clean_tree(root_node)
26
+
27
+ puts root_node.inspect if $parser_debug
28
+
29
+ root_node
30
+ end
31
+
32
+ def cc_parser
33
+ @parser
34
+ end
35
+
36
+ def clean_tree(root_node)
37
+ return if(root_node.elements.nil?)
38
+ root_node.elements.delete_if { |node| !node.is_a?(CopperNode) }
39
+ root_node.elements.each { |node| self.clean_tree(node) }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Copper
2
+ class Range < CopperNode
3
+
4
+ include ::Copper::ExpressionUtils
5
+
6
+ def value(vars = {})
7
+ lhs = elements[0].value(vars)
8
+ rhs = elements[1].value(vars)
9
+
10
+ return handle_attributes((lhs..rhs), vars)
11
+ rescue ArgumentError => exc
12
+ raise RuntimeError, "#{lhs} (#{lhs.class.name})..#{rhs} (#{rhs.class.name}) #{exc.message}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Copper
2
+ class Root < CopperNode
3
+ def value(vars = {})
4
+ result = []
5
+ elements.each do |element|
6
+ parse_result = element.value(vars)
7
+ result << parse_result unless parse_result.nil?
8
+ end
9
+
10
+ return result
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Copper
2
+ class RuleDefinition < CopperNode
3
+
4
+ def value(vars = {})
5
+ rules = vars[:rules] || []
6
+ t = {}
7
+ t[:name] = elements[0].value(vars)
8
+
9
+ raise ParseError, "a rule named #{t[:name]} already exists" if rules.detect { |x| x[:name] == t[:name] }
10
+
11
+ t[:outcome] = elements[2].value(vars)
12
+ t[:action] = elements[1].value(vars)
13
+
14
+ rules << t
15
+ vars[:rules] = rules
16
+
17
+ return t
18
+ end
19
+
20
+ end
21
+ end
data/lib/copper/set.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Copper
2
+ class Set < CopperNode
3
+
4
+ include ::Copper::ExpressionUtils
5
+
6
+ def value(vars = {})
7
+ return handle_attributes(elements[0].value(vars), vars)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Copper
2
+ class SingleVarDefinition < CopperNode
3
+ RESERVED_VARS = [:semver, :array, :string]
4
+
5
+ def value(vars = {})
6
+ variables = vars[:variables] || {}
7
+
8
+ lhr = elements[0].value(vars)
9
+ rhs = elements[1].value(vars)
10
+
11
+ # check for resevered words
12
+ raise ::Copper::RuntimeError, "#{lhr} is a reserved word" if ::Copper::SingleVarDefinition::RESERVED_VARS.include?(lhr.to_sym)
13
+
14
+ variables[lhr.to_sym] = rhs
15
+ vars[:variables] = variables
16
+
17
+ return nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Copper
2
+ # Node class for a simple string.
3
+ class String < CopperNode
4
+
5
+ include ::Copper::ExpressionUtils
6
+
7
+ def value(vars = {})
8
+ return handle_attributes(elements[0].value(vars), vars)
9
+ end
10
+ end
11
+
12
+ class StringContent < CopperNode
13
+ def value(vars = {})
14
+ return text_value
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Copper
2
+ class VarDefinition < CopperNode
3
+ def value(vars = {})
4
+ elements.each do |element|
5
+ element.value(vars)
6
+ end
7
+
8
+ return nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Copper
2
+ class Variable < CopperNode
3
+ include ::Copper::ExpressionUtils
4
+
5
+ def value(vars = {})
6
+ return handle_attributes(elements[0].value(vars), vars)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Copper
2
+ class VariableIdentifier < CopperNode
3
+
4
+ def value(vars = {})
5
+ variables = vars[:variables] || {}
6
+ identifier = self.text_value.to_sym
7
+ if variables.has_key?(identifier)
8
+ return variables[identifier]
9
+ else
10
+ raise ::Copper::ParseError, "no variable found with name #{identifier}"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Copper
2
+ VERSION = '0.0.1'
3
+ COPYRIGHT_MESSAGE = "(c) 2018 Cloud66 Inc."
4
+ APP_NAME = 'Copper'
5
+ end
data/lib/copper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'copper/version'
2
+ require_relative 'copper/loader'
3
+
4
+ module Copper
5
+ end