c66-copper 0.0.1
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/README.md +5 -0
- data/bin/console +14 -0
- data/bin/copper +96 -0
- data/bin/setup +8 -0
- data/lib/copper/action.rb +9 -0
- data/lib/copper/attribute.rb +30 -0
- data/lib/copper/attribute_params.rb +9 -0
- data/lib/copper/attributes.rb +21 -0
- data/lib/copper/attributes_right_associated.rb +11 -0
- data/lib/copper/boolean.rb +9 -0
- data/lib/copper/comparison.rb +58 -0
- data/lib/copper/compop.rb +8 -0
- data/lib/copper/copper.rb +32 -0
- data/lib/copper/copper_node.rb +16 -0
- data/lib/copper/data_types/array.rb +61 -0
- data/lib/copper/data_types/data_type.rb +54 -0
- data/lib/copper/data_types/ip_addr.rb +82 -0
- data/lib/copper/data_types/range.rb +17 -0
- data/lib/copper/data_types/semver.rb +45 -0
- data/lib/copper/data_types/string.rb +23 -0
- data/lib/copper/error.rb +5 -0
- data/lib/copper/expression.rb +8 -0
- data/lib/copper/expression_utils.rb +13 -0
- data/lib/copper/functions/fetch.rb +27 -0
- data/lib/copper/functions/ip_address.rb +18 -0
- data/lib/copper/grammar/copper.treetop +161 -0
- data/lib/copper/identifier.rb +9 -0
- data/lib/copper/loader.rb +13 -0
- data/lib/copper/logic.rb +14 -0
- data/lib/copper/logic_op.rb +7 -0
- data/lib/copper/logic_right_associated.rb +16 -0
- data/lib/copper/number.rb +10 -0
- data/lib/copper/param.rb +13 -0
- data/lib/copper/param_right_associated.rb +10 -0
- data/lib/copper/parser.rb +42 -0
- data/lib/copper/range.rb +15 -0
- data/lib/copper/root.rb +13 -0
- data/lib/copper/rule_definition.rb +21 -0
- data/lib/copper/set.rb +11 -0
- data/lib/copper/single_var_definition.rb +20 -0
- data/lib/copper/string.rb +17 -0
- data/lib/copper/var_definition.rb +11 -0
- data/lib/copper/variable.rb +9 -0
- data/lib/copper/variable_identifier.rb +15 -0
- data/lib/copper/version.rb +5 -0
- data/lib/copper.rb +5 -0
- 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,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)
|
data/lib/copper/logic.rb
ADDED
@@ -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
|
data/lib/copper/param.rb
ADDED
@@ -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
|
data/lib/copper/range.rb
ADDED
@@ -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
|
data/lib/copper/root.rb
ADDED
@@ -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,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,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
|