NCPrePatcher 0.2.0-x86_64-darwin-24

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.
@@ -0,0 +1,249 @@
1
+ require 'parslet'
2
+
3
+ module NCPP
4
+
5
+ #
6
+ # Parses raw text into a tree
7
+ #
8
+ class Parser < Parslet::Parser
9
+
10
+ def initialize(cmd_prefix: 'ncpp_')
11
+ @COMMAND_PREFIX = cmd_prefix
12
+ end
13
+
14
+ def parse(str, root: :line)
15
+ send(root).parse(str)
16
+ end
17
+
18
+ root :line
19
+
20
+ rule :line do
21
+ space? >>
22
+ ((str('//')|str('/*')|str('"')).absent? >> expression >> (any.repeat)).maybe >>
23
+ any.repeat
24
+ end
25
+
26
+ rule :expression do
27
+ ternary_operation | binary_operation | unary_operation | body
28
+ end
29
+
30
+ rule :body do
31
+ float | integer | boolean | null | string | command | block | array | variable
32
+ end
33
+
34
+ rule :binary_operation do
35
+ infix_expression(spaced(unary_operation|primary),
36
+ [match['*/%'], 11, :left], # mul, div, modulo
37
+ [match['+-'], 10, :left], # add, sub
38
+ [str('<<')|str('>>'), 9, :left], # bitwise left/right shift
39
+ [str('<=>'), 8, :left], # three-way comparison
40
+ [match['><'] >> str('=').maybe,
41
+ 7, :left], # relational >, ≥, <, ≤
42
+ [str('==')|str('!='), 6, :left], # relational =, ≠
43
+ [str('&&'), 2, :left], # logical AND
44
+ [str('||'), 1, :left], # logical OR
45
+ [str('&'), 5, :left], # bitwise AND
46
+ [str('^'), 4, :left], # bitwise XOR
47
+ [str('|'), 3, :left] # bitwise OR
48
+ )
49
+ end
50
+
51
+ rule :ternary_operation do
52
+ (binary_operation|unary_operation|primary).as(:cond) >> spaced(str('?')) >> primary.as(:e1) >> spaced(str(':')) >> primary.as(:e2)
53
+ end
54
+
55
+ rule :unary_operation do
56
+ match['!~\\-+*'].as(:op) >> primary.as(:e)
57
+ end
58
+
59
+ rule :primary do
60
+ chained_command | command | variable | group | float | integer
61
+ end
62
+
63
+ rule(:group) { lparen >> (expression.as(:group) | str('').as(:empty_group)) >> rparen >> lbrace.absent? }
64
+
65
+ rule(:identifier) { digits.absent? >> match['A-Za-z0-9_'].repeat(1) }
66
+
67
+ rule :command do
68
+ str(@COMMAND_PREFIX).maybe >> identifier.as(:cmd_name) >>
69
+ lparen >>
70
+ (expression >> (comma >> expression).repeat).repeat.as(:args) >>
71
+ rparen.as(:__last_char__) >> subscript.maybe
72
+ end
73
+
74
+ rule(:boolean) { (str('true') | str('false')).as(:bool) }
75
+
76
+ rule(:null) { (str('nil') | str('NULL')).as(:nil) }
77
+
78
+ rule :variable do
79
+ str(@COMMAND_PREFIX).maybe >> identifier.as(:var_name) >> lparen.absent? >> subscript.maybe
80
+ end
81
+
82
+ rule :block do
83
+ block_args.maybe >> lbrace >> expression.repeat.as(:block_body) >> rbrace >> subscript.maybe
84
+ end
85
+
86
+ rule :block_args do
87
+ lparen >>
88
+ (identifier >> (comma >> identifier).repeat).as(:block_args).maybe >>
89
+ rparen
90
+ end
91
+
92
+ # rule :block_sequence do
93
+ # block_args.maybe >> lbrace >>
94
+ # (block >> (comma >> block).repeat).as(:block_sequence) >>
95
+ # rbrace >> subscript.maybe
96
+ # end
97
+
98
+ rule :array do
99
+ lbracket >>
100
+ (expression >> (comma >> expression).repeat).maybe.as(:array) >>
101
+ rbracket >> subscript.maybe
102
+ end
103
+
104
+ rule :chained_command do
105
+ (command|boolean|null|variable|group|block|array|float|integer|string).as(:base) >>
106
+ (str('.') >> command.as(:next)).repeat.as(:chain) >> subscript.maybe
107
+ end
108
+
109
+ rule :subscript do
110
+ lbracket >> expression.as(:subscript_idx) >> rbracket
111
+ end
112
+
113
+ rule(:space) { match['\s'].repeat(1) }
114
+ rule(:space?) { space.maybe }
115
+
116
+ def spaced(atom)
117
+ space? >> atom >> space?
118
+ end
119
+
120
+ rule(:comma) { spaced(str(',')) }
121
+ rule(:lparen) { spaced(str('(')) }
122
+ rule(:rparen) { spaced(str(')')) }
123
+ rule(:lbrace) { spaced(str('{')) }
124
+ rule(:rbrace) { spaced(str('}')) }
125
+ rule(:lbracket) { spaced(str('[')) }
126
+ rule(:rbracket) { spaced(str(']')) }
127
+ rule(:newline) { str("\n") >> str("\r").maybe }
128
+ rule(:eol) { str("\n") | any.absent? }
129
+ rule(:digit) { match['0-9'] }
130
+ rule(:digits) { digit.repeat(1) }
131
+ rule(:hex_digit) { match['0-9a-fA-F'] }
132
+ rule(:hex_digits) { hex_digit.repeat(1) }
133
+ rule(:bin_digit) { match['0-1'] }
134
+ rule(:bin_digits) { bin_digit.repeat(1) }
135
+
136
+ rule :float do
137
+ (digits.maybe >>
138
+ (
139
+ (
140
+ str('.')|str('e')) >>
141
+ match['+-'].maybe >> digits
142
+ ) >>
143
+ (
144
+ str('e') >>
145
+ match['+-'].maybe >>
146
+ digits
147
+ ).maybe
148
+ ).as(:float) >> space?
149
+ end
150
+
151
+ rule :integer do
152
+ (
153
+ (
154
+ (str('0x') >> hex_digits) |
155
+ (str('0b') >> bin_digits) |
156
+ digits)
157
+ ).as(:integer) >> space?
158
+ end
159
+
160
+ rule :string do
161
+ (str('"') >> (
162
+ str('\\') >> any | str('"').absent? >> any
163
+ ).repeat.as(:string) >> str('"')) |
164
+ (str("'") >> (
165
+ str('\\') >> any | str("'").absent? >> any
166
+ ).repeat.as(:string) >> str("'")) >> subscript.maybe
167
+ end
168
+
169
+ end
170
+
171
+ #
172
+ # Transforms parsed trees to ASTs
173
+ #
174
+ class Transformer < Parslet::Transform
175
+ rule(integer: simple(:x)) { Integer(x) }
176
+ rule(float: simple(:x)) { Float(x) }
177
+ rule(string: simple(:s)) { String(s) }
178
+ rule(string: sequence(:s)) { '' }
179
+
180
+ rule(array: subtree(:a)) do
181
+ { array:
182
+ case a
183
+ when nil then []
184
+ when Array then a
185
+ else [a]
186
+ end
187
+ }
188
+ end
189
+
190
+ rule(group: subtree(:g)) { g }
191
+ rule(empty_group: simple(:g)) { nil }
192
+
193
+ rule(l: subtree(:lhs), o: simple(:op), r: subtree(:rhs)) do
194
+ { infix: true, lhs: lhs, op: op.to_s, rhs: rhs }
195
+ end
196
+
197
+ rule(cond: subtree(:cond), e1: subtree(:e1), e2: subtree(:e2)) do
198
+ { cond: cond, e1: e1, e2: e2 }
199
+ end
200
+
201
+ rule(op: simple(:op), e: subtree(:e)) do
202
+ { op: op.to_s, e: e }
203
+ end
204
+
205
+ rule(cmd_name: simple(:n), args: subtree(:a)) do
206
+ args =
207
+ case a
208
+ when nil then []
209
+ when Array then a
210
+ else [a]
211
+ end
212
+
213
+ { cmd_name: n.to_s, args: args }
214
+ end
215
+
216
+ rule(base: subtree(:b), chain: sequence(:cs)) do
217
+ { base: b, chain: cs }
218
+ end
219
+
220
+ rule(block_body: subtree(:exprs)) do
221
+ { block:
222
+ case exprs
223
+ when nil
224
+ []
225
+ when Array
226
+ exprs.compact
227
+ else
228
+ [exprs]
229
+ end
230
+ }
231
+ end
232
+
233
+ rule(block_args: simple(:args), block_body: subtree(:exprs)) do
234
+ { block:
235
+ case exprs
236
+ when nil
237
+ []
238
+ when Array
239
+ exprs.compact
240
+ else
241
+ [exprs]
242
+ end,
243
+ args: args.to_s.split(',').map(&:strip)
244
+ }
245
+ end
246
+
247
+ end
248
+
249
+ end
data/lib/ncpp/types.rb ADDED
@@ -0,0 +1,68 @@
1
+ require_relative 'utils.rb'
2
+
3
+ module NCPP
4
+
5
+ Block = Struct.new(:ast, :argns, :interpreter, :subs, :name) do
6
+ def eval(args)
7
+ result = nil
8
+ ast.each do |node|
9
+ if subs.nil?
10
+ result = interpreter.eval_expr(node, args.empty? || argns.nil? ? nil : Hash[argns.zip(args)])
11
+ else
12
+ result = interpreter.eval_expr(node, args.empty? || argns.nil? ? subs : subs.merge(Hash[argns.zip(args)]))
13
+ end
14
+ end
15
+ result
16
+ end
17
+
18
+ def call(*args) = eval(args)
19
+
20
+ # if no_cache.nil? && pure?
21
+ # @cache ||= {}
22
+ # return @cache[args] if @cache.key?(args)
23
+ # result = eval(args)
24
+ # @cache[args] = result
25
+ # return result
26
+ # else
27
+ # return eval(args)
28
+ # end
29
+
30
+ def return_type = Object
31
+
32
+ def arg_names = argns
33
+
34
+ def pure?
35
+ @pure unless @pure.nil?
36
+ @pure = !ast.any? { |n| interpreter.node_impure?(n, name) }
37
+ end
38
+ end
39
+
40
+ # The following are not yet (and may never be) implemented
41
+
42
+ Boolean = Struct.new(:truthy) do
43
+ def true? = truthy
44
+ def false? = !truthy
45
+ end
46
+
47
+ class CodeLoc
48
+ attr_reader :addr, :ov, :code_bin
49
+
50
+ def initialize(loc, ov = nil)
51
+ @addr, @ov, @code_bin = Utils::resolve_code_loc(loc, ov)
52
+ end
53
+ end
54
+
55
+ class AsmFunc
56
+ attr_reader :instructions, :labels, :literal_pool
57
+
58
+ def initialize(instructions, labels, literal_pool)
59
+ @instructions = instructions
60
+ @labels = labels
61
+ @literal_pool = literal_pool
62
+ end
63
+
64
+ def to_s(reloc: true)
65
+ end
66
+ end
67
+
68
+ end