flexr 1.0.0 → 1.1.0

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +74 -28
  3. data/benchmark/golden/calculator_lexer.sha256 +1 -1
  4. data/benchmark/golden/json_lexer.sha256 +1 -1
  5. data/benchmark/golden/regexp_tokenizer.sha256 +1 -1
  6. data/benchmark/golden/ruby_subset_lexer.sha256 +1 -1
  7. data/benchmark/golden/toy_lang_lexer.sha256 +1 -1
  8. data/benchmark/golden/with_lrama_lexer.sha256 +1 -1
  9. data/benchmark/golden/with_racc_lexer.sha256 +1 -1
  10. data/docs/README.md +2 -1
  11. data/docs/explanation/backends.md +13 -10
  12. data/docs/explanation/matching-semantics.md +4 -2
  13. data/docs/explanation/security-model.md +10 -3
  14. data/docs/explanation/unicode-and-encoding.md +3 -1
  15. data/docs/how-to/deploy-a-standalone-lexer.md +5 -3
  16. data/docs/how-to/generate-a-lexer.md +3 -3
  17. data/docs/how-to/handle-errors.md +4 -1
  18. data/docs/how-to/run-a-lexer-at-runtime.md +5 -0
  19. data/docs/how-to/track-token-locations.md +2 -1
  20. data/docs/how-to/tune-performance.md +3 -3
  21. data/docs/perf-log.md +16 -0
  22. data/docs/reference/actions.md +5 -2
  23. data/docs/reference/diagnostics.md +8 -0
  24. data/docs/reference/dsl.md +19 -5
  25. data/docs/reference/errors.md +6 -3
  26. data/docs/reference/generated-artifacts.md +29 -2
  27. data/docs/reference/public-api.md +7 -2
  28. data/docs/reference/regexp.md +8 -6
  29. data/docs/reference/runtime.md +20 -3
  30. data/docs/reference/tokens-and-locations.md +6 -4
  31. data/docs/releases/v1.1.0.md +44 -0
  32. data/lib/flexr/action_resolver.rb +15 -0
  33. data/lib/flexr/artifact_writer.rb +61 -0
  34. data/lib/flexr/automaton/accel.rb +9 -4
  35. data/lib/flexr/automaton/analysis.rb +47 -6
  36. data/lib/flexr/automaton/backend_cost_model.rb +40 -0
  37. data/lib/flexr/automaton/compiler.rb +50 -71
  38. data/lib/flexr/automaton/dfa.rb +106 -19
  39. data/lib/flexr/automaton/minimizer.rb +79 -31
  40. data/lib/flexr/automaton/nfa.rb +45 -13
  41. data/lib/flexr/automaton/types.rb +14 -0
  42. data/lib/flexr/cli.rb +11 -5
  43. data/lib/flexr/codegen/direct.rb +5 -41
  44. data/lib/flexr/codegen/table.rb +175 -69
  45. data/lib/flexr/codegen.rb +8 -0
  46. data/lib/flexr/configuration.rb +37 -0
  47. data/lib/flexr/dsl.rb +105 -39
  48. data/lib/flexr/errors.rb +1 -0
  49. data/lib/flexr/generated.rb +61 -35
  50. data/lib/flexr/generator.rb +47 -82
  51. data/lib/flexr/importer.rb +4 -40
  52. data/lib/flexr/options.rb +5 -3
  53. data/lib/flexr/rake_task.rb +6 -1
  54. data/lib/flexr/regexp/ast.rb +5 -2
  55. data/lib/flexr/regexp/normalizer.rb +62 -16
  56. data/lib/flexr/regexp/parser.rb +121 -46
  57. data/lib/flexr/regexp/tokenizer.rb +192 -67
  58. data/lib/flexr/runtime/buffer.rb +115 -9
  59. data/lib/flexr/runtime/core.rb +214 -47
  60. data/lib/flexr/runtime/errors.rb +64 -4
  61. data/lib/flexr/runtime/interpreter.rb +178 -71
  62. data/lib/flexr/runtime.rb +70 -0
  63. data/lib/flexr/source/passthrough.rb +62 -9
  64. data/lib/flexr/source/prism_reader.rb +175 -46
  65. data/lib/flexr/source/static_eval.rb +40 -4
  66. data/lib/flexr/source.rb +6 -0
  67. data/lib/flexr/unicode/data/properties.rb +1 -1
  68. data/lib/flexr/unicode/data.rb +11 -0
  69. data/lib/flexr/unicode/property.rb +3 -5
  70. data/lib/flexr/unicode/reference_regexp.rb +4 -0
  71. data/lib/flexr/unicode/version.rb +7 -0
  72. data/lib/flexr/version.rb +1 -1
  73. data/lib/flexr.rb +9 -76
  74. data/tools/coverage.rb +6 -1
  75. metadata +12 -1
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flexr
4
+ module Unicode
5
+ module Data
6
+ autoload :VERSION, File.expand_path("data/properties", __dir__)
7
+ autoload :PROPERTIES, File.expand_path("data/properties", __dir__)
8
+ autoload :CASE_FOLD, File.expand_path("data/case_folding", __dir__)
9
+ end
10
+ end
11
+ end
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Flexr
4
4
  module Unicode
5
- VERSION = Data::VERSION
6
-
7
5
  module Property
8
6
  ALIASES = {
9
7
  "L" => "L", "Letter" => "L", "N" => "N", "Number" => "N", "Nd" => "Nd",
@@ -21,17 +19,17 @@ module Flexr
21
19
  module_function
22
20
 
23
21
  def ranges(name, negate: false)
24
- key = [name.to_s, negate]
22
+ canonical = canonical_name(name)
23
+ key = [canonical, negate]
25
24
  return CACHE[key] if CACHE.key?(key)
26
25
 
27
- canonical = canonical_name(name)
28
26
  ranges = if canonical.start_with?("POSIX_")
29
27
  posix_ranges(canonical.delete_prefix("POSIX_"))
30
28
  else
31
29
  property_ranges(canonical, name)
32
30
  end
33
31
  ranges = complement(ranges) if negate
34
- CACHE[key] = ranges.map(&:dup).freeze
32
+ CACHE[key] = ranges.map { |range| range.dup.freeze }.freeze
35
33
  end
36
34
 
37
35
  def canonical_name(name)
@@ -30,6 +30,7 @@ module Flexr
30
30
  def source_for(node, ignorecase: false)
31
31
  case node
32
32
  when Regexp::AST::Empty, Regexp::AST::Anchor then ""
33
+ when Regexp::AST::Fail then "(?!)"
33
34
  when Regexp::AST::ByteRange then byte_class([[node.lo, node.hi]])
34
35
  when Regexp::AST::CodepointRange then codepoint_class([[node.lo, node.hi]])
35
36
  when Regexp::AST::CharClass
@@ -48,6 +49,9 @@ module Flexr
48
49
  when Regexp::AST::Alt
49
50
  "(?:#{node.children.map { |child| source_for(child, ignorecase: ignorecase) }.join('|')})"
50
51
  when Regexp::AST::Star then "(?:#{source_for(node.child, ignorecase: ignorecase)})*"
52
+ when Regexp::AST::Repeat
53
+ maximum = node.maximum.nil? ? "" : node.maximum
54
+ "(?:#{source_for(node.child, ignorecase: ignorecase)}){#{node.minimum},#{maximum}}"
51
55
  else
52
56
  raise CompileError, "unsupported reference AST node: #{node.class}"
53
57
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flexr
4
+ module Unicode
5
+ VERSION = "15.1.0"
6
+ end
7
+ end
data/lib/flexr/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flexr
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/flexr.rb CHANGED
@@ -1,81 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
- require "digest"
5
- require_relative "flexr/version"
6
- require_relative "flexr/errors"
7
- require_relative "flexr/diagnostics"
8
- require_relative "flexr/ir"
9
- require_relative "flexr/regexp/ast"
10
- require_relative "flexr/regexp/parser"
11
- require_relative "flexr/regexp/normalizer"
12
- require_relative "flexr/regexp/unsupported"
13
- require_relative "flexr/regexp/char_class"
14
- require_relative "flexr/unicode/utf8_splitter"
15
- require_relative "flexr/unicode/data/properties"
16
- require_relative "flexr/unicode/data/case_folding"
17
- require_relative "flexr/unicode/property"
18
- require_relative "flexr/unicode/reference_regexp"
19
- require_relative "flexr/unicode/case_fold"
20
- require_relative "flexr/automaton/byte_class_set"
21
- require_relative "flexr/automaton/nfa"
22
- require_relative "flexr/automaton/dfa"
23
- require_relative "flexr/automaton/compiler"
24
- require_relative "flexr/automaton/analysis"
25
- require_relative "flexr/automaton/minimizer"
26
- require_relative "flexr/automaton/accel"
27
- require_relative "flexr/codegen/base"
28
- require_relative "flexr/codegen/table"
29
- require_relative "flexr/codegen/direct"
30
- require_relative "flexr/codegen/firstmatch"
31
- require_relative "flexr/codegen/table_packer"
32
- require_relative "flexr/runtime/location"
33
- require_relative "flexr/runtime/token"
34
- require_relative "flexr/runtime/buffer"
35
- require_relative "flexr/runtime/errors"
36
- require_relative "flexr/runtime/interpreter"
37
- require_relative "flexr/runtime/core"
38
- require_relative "flexr/dsl"
39
- require_relative "flexr/lexer"
40
- require_relative "flexr/generated"
41
- require_relative "flexr/source/static_eval"
42
- require_relative "flexr/source/prism_reader"
43
- require_relative "flexr/source/passthrough"
44
- require_relative "flexr/importer"
45
- require_relative "flexr/generator"
46
- require_relative "flexr/options"
47
- require_relative "flexr/rake_task"
48
- require_relative "flexr/cli"
3
+ require_relative "flexr/runtime"
49
4
 
50
5
  module Flexr
51
- class << self
52
- def compile_pattern(pattern, options: {})
53
- regexp = pattern.is_a?(::Regexp) ? pattern : ::Regexp.new(pattern.to_s)
54
- return Automaton::ReferenceDFA.new(regexp, unicode: options[:unicode] == true) if
55
- reference_pattern?(regexp, unicode: options[:unicode] == true)
56
- encoding = regexp.encoding == Encoding::BINARY ? Encoding::BINARY : Encoding::UTF_8
57
- rule = IR::Rule.new(index: 0, patterns: [regexp], action: :skip, states: [:initial])
58
- state = IR::State.new(name: :initial, inclusive: true, id: 0)
59
- spec = IR::Spec.new(
60
- class_name: "Pattern", backend: :table, token_kind: :array,
61
- encoding: encoding, options: options, declared_tokens: [],
62
- states: { initial: state }, rules: [rule], eof_rules: {}, verbatim: nil
63
- )
64
- Automaton::Compiler.new(spec).compile.machines.fetch(:initial).dfa
65
- end
66
-
67
- def reference_pattern?(regexp, unicode: false)
68
- return true if regexp.source.match?(/\\[pP]\{/) || regexp.source.match?(/\[:(?:\^)?[a-z]+:\]/)
69
-
70
- unicode && regexp.encoding != Encoding::BINARY && regexp.source.match?(/\\[dDwWsS]/)
71
- end
72
-
73
- def parse_pattern(pattern, options: {})
74
- regexp = pattern.is_a?(::Regexp) ? pattern : ::Regexp.new(pattern.to_s)
75
- encoding = regexp.encoding == Encoding::BINARY ? Encoding::BINARY : Encoding::UTF_8
76
- ast = Regexp::Parser.new(regexp.source, options: regexp.options, encoding: encoding,
77
- unicode: options[:unicode] == true).parse
78
- Regexp::Normalizer.new(ast, encoding: encoding, options: regexp.options).normalize
79
- end
80
- end
6
+ autoload :ArtifactWriter, File.expand_path("flexr/artifact_writer", __dir__)
7
+ autoload :Codegen, File.expand_path("flexr/codegen", __dir__)
8
+ autoload :Source, File.expand_path("flexr/source", __dir__)
9
+ autoload :Generator, File.expand_path("flexr/generator", __dir__)
10
+ autoload :Importer, File.expand_path("flexr/importer", __dir__)
11
+ autoload :Options, File.expand_path("flexr/options", __dir__)
12
+ autoload :RakeTask, File.expand_path("flexr/rake_task", __dir__)
13
+ autoload :CLI, File.expand_path("flexr/cli", __dir__)
81
14
  end
data/tools/coverage.rb CHANGED
@@ -7,7 +7,12 @@ Coverage.start(lines: true)
7
7
 
8
8
  status = RSpec::Core::Runner.run(["spec", "--format", "progress", "--no-color"], File::NULL, $stdout)
9
9
  result = Coverage.result
10
- files = Dir[File.expand_path("../lib/flexr/**/*.rb", __dir__)]
10
+ files = Dir[File.expand_path("../lib/flexr/**/*.rb", __dir__)].reject do |file|
11
+ # Generated artifacts duplicate the scanner template's executable lines.
12
+ # Their behavior is exercised by the suite, while the template is counted
13
+ # once as the maintainable source of those lines.
14
+ File.foreach(file).first(3).any? { |line| line.include?("Generated by flexr") }
15
+ end
11
16
  totals = files.map do |file|
12
17
  lines = result.fetch(file, {}).fetch(:lines, [])
13
18
  executable = lines.count { |count| !count.nil? }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
@@ -77,6 +77,7 @@ files:
77
77
  - docs/reference/regexp.md
78
78
  - docs/reference/runtime.md
79
79
  - docs/reference/tokens-and-locations.md
80
+ - docs/releases/v1.1.0.md
80
81
  - docs/tutorial/build-a-calculator-lexer.md
81
82
  - examples/calculator/README.md
82
83
  - examples/calculator/lexer.flexr.rb
@@ -92,19 +93,25 @@ files:
92
93
  - examples/with_racc/lexer.flexr.rb
93
94
  - exe/flexr
94
95
  - lib/flexr.rb
96
+ - lib/flexr/action_resolver.rb
97
+ - lib/flexr/artifact_writer.rb
95
98
  - lib/flexr/automaton/accel.rb
96
99
  - lib/flexr/automaton/analysis.rb
100
+ - lib/flexr/automaton/backend_cost_model.rb
97
101
  - lib/flexr/automaton/byte_class_set.rb
98
102
  - lib/flexr/automaton/compiler.rb
99
103
  - lib/flexr/automaton/dfa.rb
100
104
  - lib/flexr/automaton/minimizer.rb
101
105
  - lib/flexr/automaton/nfa.rb
106
+ - lib/flexr/automaton/types.rb
102
107
  - lib/flexr/cli.rb
108
+ - lib/flexr/codegen.rb
103
109
  - lib/flexr/codegen/base.rb
104
110
  - lib/flexr/codegen/direct.rb
105
111
  - lib/flexr/codegen/firstmatch.rb
106
112
  - lib/flexr/codegen/table.rb
107
113
  - lib/flexr/codegen/table_packer.rb
114
+ - lib/flexr/configuration.rb
108
115
  - lib/flexr/diagnostics.rb
109
116
  - lib/flexr/dsl.rb
110
117
  - lib/flexr/errors.rb
@@ -122,16 +129,19 @@ files:
122
129
  - lib/flexr/regexp/tokenizer.flexr.rb
123
130
  - lib/flexr/regexp/tokenizer.rb
124
131
  - lib/flexr/regexp/unsupported.rb
132
+ - lib/flexr/runtime.rb
125
133
  - lib/flexr/runtime/buffer.rb
126
134
  - lib/flexr/runtime/core.rb
127
135
  - lib/flexr/runtime/errors.rb
128
136
  - lib/flexr/runtime/interpreter.rb
129
137
  - lib/flexr/runtime/location.rb
130
138
  - lib/flexr/runtime/token.rb
139
+ - lib/flexr/source.rb
131
140
  - lib/flexr/source/passthrough.rb
132
141
  - lib/flexr/source/prism_reader.rb
133
142
  - lib/flexr/source/static_eval.rb
134
143
  - lib/flexr/unicode/case_fold.rb
144
+ - lib/flexr/unicode/data.rb
135
145
  - lib/flexr/unicode/data/LICENSE-UNICODE.txt
136
146
  - lib/flexr/unicode/data/UNICODE_VERSION
137
147
  - lib/flexr/unicode/data/case_folding.rb
@@ -139,6 +149,7 @@ files:
139
149
  - lib/flexr/unicode/property.rb
140
150
  - lib/flexr/unicode/reference_regexp.rb
141
151
  - lib/flexr/unicode/utf8_splitter.rb
152
+ - lib/flexr/unicode/version.rb
142
153
  - lib/flexr/version.rb
143
154
  - site/README.md
144
155
  - site/astro.config.mjs