gpp 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 768357e29236ee25c7bdfad581346d092c16ffea
4
- data.tar.gz: a17f96873ebdf6f6e8db3bd8ae108e909f4c7f36
3
+ metadata.gz: 539e909aab402cd55e8238e07e0f70e691716751
4
+ data.tar.gz: f3982fd692c0fb4df5a66b42abf53cb2d4715ee3
5
5
  SHA512:
6
- metadata.gz: 85c4310438cd96db69747dca9c31c1de02dccbc385d691bacfd044722281fabff8c39210f2caa1719bfb3f755fa20015309257b1c178d1fd79df9796602ccfd9
7
- data.tar.gz: 6140d1bc380ede98ca30cc49fcc2450c8799b0bc1430a6b2becea8a01bd71cf61117feeac3c96cd25dc5d471affd9419028462007265986ee1617fc518d6a527
6
+ metadata.gz: 29e53154b0804e2f60f62755a5ffd6b22e244f9d6f7212895076c8e9c43ae0b90ad85e8c3f5a786b917c70e2e2d8677ea22849faccc22ae5492213be6d1f812d
7
+ data.tar.gz: f27500f9231e066812ede4af8c26716e73cec2cb6216ee5150c9ea6275a7289f6fc7073f23d530d2c01ec9225262d88f366d7f6eb0ab4b5827122455bc66888b
data/bin/gpp CHANGED
@@ -3,15 +3,26 @@ require 'gpp'
3
3
  require 'pathname'
4
4
  require 'optparse'
5
5
 
6
+ from, to = nil, nil
7
+
6
8
  OptionParser.new do |opts|
7
9
  opts.version = GPP::VERSION
8
10
  opts.banner = "Usage: #{opts.program_name} [-hv] [files]"
11
+ opts.on "-r PATTERN" do |value|
12
+ _, from, to = value.split("/")
13
+ from = /#{from}/
14
+ end
9
15
  end.order!
10
16
 
11
17
  args = ARGV.empty? ? ["-"] : ARGV
12
18
 
13
19
  args.each do |arg|
14
20
  file = arg == "-" ? STDIN.read : File.read(arg)
15
- rpp = GPP::Processor.new(file, STDOUT)
21
+ out = if from
22
+ File.open(arg.gsub(from, to), "w")
23
+ else
24
+ STDOUT
25
+ end
26
+ rpp = GPP::Processor.new(file, out, arg, 1)
16
27
  rpp.scan_all
17
28
  end
@@ -3,10 +3,15 @@ require 'strscan'
3
3
  module GPP
4
4
  class Processor < StringScanner
5
5
 
6
- def initialize (in_, out, defs = {})
6
+ attr_reader :path, :trace
7
+
8
+ def initialize (in_, out, path, offset, defs = {}, trace = [])
7
9
  super(in_)
8
10
  @out = out
9
11
  @defs = defs.to_h
12
+ @path = path
13
+ @offset = offset
14
+ @trace = trace
10
15
  end
11
16
 
12
17
  def loopcat (into = "")
@@ -40,9 +45,18 @@ module GPP
40
45
  end
41
46
  end
42
47
 
43
- def scan_word (bare = /\S+/)
44
- if scan(/{\n?/)
45
- scan_block()
48
+ def indent_block (block, indent)
49
+ block.gsub(/^\n/, "").gsub(/\n$/, "").gsub("\n", "\n#{indent}")
50
+ end
51
+
52
+ def undent_block (block)
53
+ indent = block[/\A\n[ \t]+/]
54
+ indent ? block.gsub(/#{indent}/, "\n") : block
55
+ end
56
+
57
+ def scan_arg (bare = /\S+/)
58
+ if scan(/{/)
59
+ undent_block(scan_block())
46
60
  elsif scan(/"/)
47
61
  scan_string()
48
62
  else
@@ -52,84 +66,117 @@ module GPP
52
66
 
53
67
  def scan_args
54
68
  if scan(/\(/)
55
- loopcat [] do
69
+ scan(/[ \t]+/)
70
+ loopcat [scan_arg(/[^,)]*/)] do
56
71
  if scan(/\)/)
57
72
  nil
58
- else
59
- scan_word(/[^,)]+/).tap do
60
- scan(/,/)
61
- end
73
+ elsif scan(/,/)
74
+ scan(/[ \t]+/)
75
+ scan_arg(/[^,)]*/)
62
76
  end
63
77
  end
64
78
  else
65
79
  loopcat [] do
66
- if scan(/\n/)
80
+ if scan(/(?=\n)/)
67
81
  nil
68
82
  else
69
- scan(/ +/)
70
- scan_word
83
+ scan(/[ \t]+/)
84
+ scan_arg
71
85
  end
72
86
  end
73
87
  end
74
88
  end
75
89
 
76
- def run (string, args = nil)
90
+ def run (string, args, path, line)
91
+ trace = self.trace + [tracer]
77
92
  if args == nil
78
- self.class.new(string, s = "", @defs).scan_all
93
+ self.class.new(string, s = "", path, line, @defs, trace).scan_all
79
94
  else
80
- self.class.new(string, s = "", @defs.merge(args.to_h)).scan_all
95
+ self.class.new(string, s = "", path, line, @defs.merge(args.to_h), trace).scan_all
81
96
  end
82
97
  s
83
98
  end
84
99
 
85
- def run_block (args, body)
86
- theargs = scan_args
87
- run(body, args.zip(theargs))
88
- end
100
+ Definition = Struct.new(:type, :args, :body, :path, :line)
89
101
 
90
102
  def run_macro (id)
91
- if d = @defs[id]
92
- if d.is_a?(String)
93
- run(d)
94
- else
95
- theargs = scan_args
96
- run(d[1], d[0].zip(theargs))
103
+ rpos = pos - id.length - 2
104
+ w = string[(string.rindex("\n", rpos) || 0) + 1..rpos][/[ \t]+/]
105
+ res = if d = @defs[id]
106
+ case d.type
107
+ when :var
108
+ run(d.body, {}, d.path, d.line)
109
+ when :fun
110
+ args = scan_args.map{|arg| Definition.new(:var, {}, run(arg, {}, path, line), path, line)}
111
+ if d.args[-1] == "..."
112
+ la = d.args.length - 1
113
+ args[la..-1] = Definition.new(:var, {}, args[la..-1].map(&:body).join(" "), args[la].path, args[la].line)
114
+ end
115
+ if args.length != d.args.length
116
+ error "wrong argument count for #{id}: expected #{d.args.length} but got #{args.length}"
117
+ end
118
+ run(d.body, d.args.zip(args), d.path, d.line)
97
119
  end
98
120
  else
99
- STDERR.puts "undefined macro: #{id}"
100
- exit 1
121
+ error "undefined macro: #{id}"
101
122
  end
123
+ indent_block(res, w)
102
124
  end
103
125
 
104
126
  def scan_define
127
+ line = self.line
105
128
  name, *args, body = scan_args
106
- @defs[name] = [args, body]
129
+ if args == []
130
+ @defs[name] = Definition.new(:var, nil, body, @path, line)
131
+ else
132
+ @defs[name] = Definition.new(:fun, args, body, @path, line)
133
+ end
107
134
  end
108
135
 
109
136
  def scan_import ()
110
137
  args = scan_args
111
138
  args.each do |arg|
112
- run File.read(arg)
139
+ run File.read(arg), nil, arg, 1
113
140
  end
114
141
  end
115
142
 
116
143
  def scan_all
117
- scan(/\s+/)
118
144
  while !eos?
119
145
  @out << (scan(/[^#@]+/) || "")
120
146
  if scan(/#define\b/)
121
147
  scan_define
148
+ scan(/\s+/)
122
149
  elsif scan(/#import\b/)
123
150
  scan_import
151
+ scan(/\s+/)
152
+ #elsif scan(/#(\w+)/)
153
+ # error "undefined meta-macro: #{self[1]}"
124
154
  elsif scan(/@@/)
125
155
  @out << "@"
126
- elsif scan(/@(\w+)/)
156
+ elsif scan(/@(\.\.\.|\w+)/)
127
157
  @out << (run_macro(self[1]) || "")
128
- else
129
- scan(/./)
158
+ elsif s = scan(/./)
159
+ @out << s
130
160
  end
131
161
  end
132
162
  end
133
163
 
164
+ def line
165
+ @offset + string[0..pos - 1].count("\n")
166
+ end
167
+
168
+ def tracer
169
+ [path, line]
170
+ end
171
+
172
+ def error (message)
173
+ STDERR.puts "#{message}"
174
+ STDERR.puts " in #{path}:#{line}"
175
+ trace.reverse.each do |path, line|
176
+ STDERR.puts " #{path}:#{line}"
177
+ end
178
+ exit 1
179
+ end
180
+
134
181
  end
135
182
  end
@@ -1,3 +1,3 @@
1
1
  module GPP
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gpp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Baum
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-11 00:00:00.000000000 Z
11
+ date: 2015-12-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A text pre-processor
14
14
  email: n@p12a.org.uk