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