csv_plus_plus 0.1.3 → 0.2.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -3
  3. data/docs/CHANGELOG.md +18 -0
  4. data/lib/csv_plus_plus/a1_reference.rb +202 -0
  5. data/lib/csv_plus_plus/benchmarked_compiler.rb +3 -3
  6. data/lib/csv_plus_plus/cell.rb +1 -35
  7. data/lib/csv_plus_plus/cli.rb +43 -80
  8. data/lib/csv_plus_plus/cli_flag.rb +77 -70
  9. data/lib/csv_plus_plus/color.rb +1 -1
  10. data/lib/csv_plus_plus/compiler.rb +31 -21
  11. data/lib/csv_plus_plus/entities/ast_builder.rb +11 -4
  12. data/lib/csv_plus_plus/entities/boolean.rb +16 -9
  13. data/lib/csv_plus_plus/entities/builtins.rb +68 -40
  14. data/lib/csv_plus_plus/entities/date.rb +14 -11
  15. data/lib/csv_plus_plus/entities/entity.rb +11 -29
  16. data/lib/csv_plus_plus/entities/entity_with_arguments.rb +18 -31
  17. data/lib/csv_plus_plus/entities/function.rb +22 -11
  18. data/lib/csv_plus_plus/entities/function_call.rb +35 -11
  19. data/lib/csv_plus_plus/entities/has_identifier.rb +19 -0
  20. data/lib/csv_plus_plus/entities/number.rb +15 -10
  21. data/lib/csv_plus_plus/entities/reference.rb +77 -0
  22. data/lib/csv_plus_plus/entities/runtime_value.rb +36 -23
  23. data/lib/csv_plus_plus/entities/string.rb +13 -10
  24. data/lib/csv_plus_plus/entities.rb +2 -18
  25. data/lib/csv_plus_plus/error/cli_error.rb +17 -0
  26. data/lib/csv_plus_plus/error/compiler_error.rb +17 -0
  27. data/lib/csv_plus_plus/error/error.rb +18 -5
  28. data/lib/csv_plus_plus/error/formula_syntax_error.rb +12 -13
  29. data/lib/csv_plus_plus/error/modifier_syntax_error.rb +10 -36
  30. data/lib/csv_plus_plus/error/modifier_validation_error.rb +6 -32
  31. data/lib/csv_plus_plus/error/positional_error.rb +15 -0
  32. data/lib/csv_plus_plus/error/writer_error.rb +1 -1
  33. data/lib/csv_plus_plus/error.rb +4 -1
  34. data/lib/csv_plus_plus/error_formatter.rb +111 -0
  35. data/lib/csv_plus_plus/google_api_client.rb +18 -8
  36. data/lib/csv_plus_plus/lexer/racc_lexer.rb +144 -0
  37. data/lib/csv_plus_plus/lexer/tokenizer.rb +53 -17
  38. data/lib/csv_plus_plus/lexer.rb +40 -1
  39. data/lib/csv_plus_plus/modifier/data_validation.rb +1 -1
  40. data/lib/csv_plus_plus/modifier/expand.rb +17 -0
  41. data/lib/csv_plus_plus/modifier.rb +6 -1
  42. data/lib/csv_plus_plus/options/file_options.rb +49 -0
  43. data/lib/csv_plus_plus/options/google_sheets_options.rb +42 -0
  44. data/lib/csv_plus_plus/options/options.rb +102 -0
  45. data/lib/csv_plus_plus/options.rb +22 -110
  46. data/lib/csv_plus_plus/parser/cell_value.tab.rb +65 -66
  47. data/lib/csv_plus_plus/parser/code_section.tab.rb +92 -84
  48. data/lib/csv_plus_plus/parser/modifier.tab.rb +40 -30
  49. data/lib/csv_plus_plus/reader/csv.rb +50 -0
  50. data/lib/csv_plus_plus/reader/google_sheets.rb +129 -0
  51. data/lib/csv_plus_plus/reader/reader.rb +27 -0
  52. data/lib/csv_plus_plus/reader/rubyxl.rb +37 -0
  53. data/lib/csv_plus_plus/reader.rb +14 -0
  54. data/lib/csv_plus_plus/runtime/graph.rb +6 -6
  55. data/lib/csv_plus_plus/runtime/{position_tracker.rb → position.rb} +16 -5
  56. data/lib/csv_plus_plus/runtime/references.rb +32 -27
  57. data/lib/csv_plus_plus/runtime/runtime.rb +73 -67
  58. data/lib/csv_plus_plus/runtime/scope.rb +280 -0
  59. data/lib/csv_plus_plus/runtime.rb +9 -9
  60. data/lib/csv_plus_plus/source_code.rb +14 -9
  61. data/lib/csv_plus_plus/template.rb +17 -12
  62. data/lib/csv_plus_plus/version.rb +1 -1
  63. data/lib/csv_plus_plus/writer/csv.rb +32 -5
  64. data/lib/csv_plus_plus/writer/excel.rb +19 -6
  65. data/lib/csv_plus_plus/writer/file_backer_upper.rb +27 -14
  66. data/lib/csv_plus_plus/writer/google_sheets.rb +23 -129
  67. data/lib/csv_plus_plus/writer/{google_sheet_builder.rb → google_sheets_builder.rb} +39 -55
  68. data/lib/csv_plus_plus/writer/merger.rb +56 -0
  69. data/lib/csv_plus_plus/writer/open_document.rb +16 -2
  70. data/lib/csv_plus_plus/writer/rubyxl_builder.rb +68 -43
  71. data/lib/csv_plus_plus/writer/writer.rb +42 -0
  72. data/lib/csv_plus_plus/writer.rb +58 -19
  73. data/lib/csv_plus_plus.rb +26 -14
  74. metadata +43 -18
  75. data/lib/csv_plus_plus/entities/cell_reference.rb +0 -231
  76. data/lib/csv_plus_plus/entities/variable.rb +0 -37
  77. data/lib/csv_plus_plus/error/syntax_error.rb +0 -71
  78. data/lib/csv_plus_plus/google_options.rb +0 -32
  79. data/lib/csv_plus_plus/lexer/lexer.rb +0 -89
  80. data/lib/csv_plus_plus/runtime/can_define_references.rb +0 -87
  81. data/lib/csv_plus_plus/runtime/can_resolve_references.rb +0 -209
  82. data/lib/csv_plus_plus/writer/base_writer.rb +0 -45
@@ -7,50 +7,37 @@ module CSVPlusPlus
7
7
  # are function calls and function definitions
8
8
  #
9
9
  # @attr_reader arguments [Array<Entity>] The arguments supplied to this entity.
10
- class EntityWithArguments < Entity
10
+ class EntityWithArguments < ::CSVPlusPlus::Entities::Entity
11
11
  extend ::T::Sig
12
+ extend ::T::Helpers
13
+ extend ::T::Generic
12
14
 
13
15
  abstract!
14
16
 
15
- sig { returns(::T::Array[::CSVPlusPlus::Entities::Entity]) }
17
+ ArgumentsType = type_member
18
+ public_constant :ArgumentsType
19
+
20
+ sig { returns(::T::Array[::CSVPlusPlus::Entities::EntityWithArguments::ArgumentsType]) }
16
21
  attr_reader :arguments
17
22
 
18
- sig do
19
- params(
20
- type: ::CSVPlusPlus::Entities::Type,
21
- id: ::T.nilable(::Symbol),
22
- arguments: ::T::Array[::CSVPlusPlus::Entities::Entity]
23
- ).void
24
- end
25
- # @param type [Entities::Type]
26
- # @param id [::String]
27
- # @param arguments [Array<Entity>]
28
- def initialize(type, id: nil, arguments: [])
29
- super(type, id:)
23
+ sig { params(arguments: ::T::Array[::CSVPlusPlus::Entities::EntityWithArguments::ArgumentsType]).void }
24
+ # @param arguments [Array<ArgumentsType>]
25
+ def initialize(arguments: [])
26
+ super()
30
27
  @arguments = arguments
31
28
  end
32
29
 
33
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
30
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
34
31
  # @param other [Entity]
35
32
  #
36
33
  # @return [boolean]
37
34
  def ==(other)
38
- return false unless other.is_a?(self.class)
39
-
40
- @arguments == other.arguments && super
41
- end
42
-
43
- protected
44
-
45
- sig do
46
- params(arguments: ::T::Array[::CSVPlusPlus::Entities::Entity])
47
- .returns(::T::Array[::CSVPlusPlus::Entities::Entity])
48
- end
49
- attr_writer :arguments
50
-
51
- sig { params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::T::Array[::String]) }
52
- def evaluate_arguments(runtime)
53
- @arguments.map { |arg| arg.evaluate(runtime) }
35
+ case other
36
+ when self.class
37
+ @arguments == other.arguments
38
+ else
39
+ false
40
+ end
54
41
  end
55
42
  end
56
43
  end
@@ -7,8 +7,15 @@ module CSVPlusPlus
7
7
  #
8
8
  # @attr_reader body [Entity] The body of the function. +body+ can contain variable references
9
9
  # from +@arguments+
10
- class Function < EntityWithArguments
10
+ class Function < ::CSVPlusPlus::Entities::EntityWithArguments
11
11
  extend ::T::Sig
12
+ include ::CSVPlusPlus::Entities::HasIdentifier
13
+
14
+ ArgumentsType = type_member { { fixed: ::Symbol } }
15
+ public_constant :ArgumentsType
16
+
17
+ sig { returns(::Symbol) }
18
+ attr_reader :id
12
19
 
13
20
  sig { returns(::CSVPlusPlus::Entities::Entity) }
14
21
  attr_reader :body
@@ -18,27 +25,31 @@ module CSVPlusPlus
18
25
  # @param arguments [Array<Symbol>]
19
26
  # @param body [Entity]
20
27
  def initialize(id, arguments, body)
21
- super(::CSVPlusPlus::Entities::Type::Function, id:, arguments: arguments.map(&:to_sym))
28
+ super(arguments: arguments.map(&:to_sym))
22
29
 
23
30
  @body = ::T.let(body, ::CSVPlusPlus::Entities::Entity)
31
+ @id = ::T.let(identifier(id), ::Symbol)
24
32
  end
25
33
 
26
- sig { override.params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
27
- # @param runtime [Runtime]
34
+ sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
35
+ # @param position [Position]
28
36
  #
29
- # @return [::String]
30
- def evaluate(runtime)
31
- "def #{@id.to_s.upcase}(#{arguments.map(&:to_s).join(', ')}) #{@body.evaluate(runtime)}"
37
+ # @return [String]
38
+ def evaluate(position)
39
+ "def #{@id.to_s.upcase}(#{arguments.map(&:to_s).join(', ')}) #{@body.evaluate(position)}"
32
40
  end
33
41
 
34
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
42
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
35
43
  # @param other [Entity]
36
44
  #
37
45
  # @return [::T::Boolean]
38
46
  def ==(other)
39
- return false unless super
40
-
41
- other.is_a?(self.class) && @body == other.body
47
+ case other
48
+ when self.class
49
+ @body == other.body && super
50
+ else
51
+ false
52
+ end
42
53
  end
43
54
  end
44
55
  end
@@ -8,26 +8,40 @@ module CSVPlusPlus
8
8
  # @attr_reader infix [boolean] Whether or not this function call is infix (X * Y, A + B, etc)
9
9
  class FunctionCall < EntityWithArguments
10
10
  extend ::T::Sig
11
+ include ::CSVPlusPlus::Entities::HasIdentifier
12
+
13
+ ArgumentsType = type_member { { fixed: ::CSVPlusPlus::Entities::Entity } }
14
+ public_constant :ArgumentsType
11
15
 
12
16
  sig { returns(::T::Boolean) }
13
17
  attr_reader :infix
14
18
 
15
- sig { params(id: ::Symbol, arguments: ::T::Array[::CSVPlusPlus::Entities::Entity], infix: ::T::Boolean).void }
19
+ sig { returns(::Symbol) }
20
+ attr_reader :id
21
+
22
+ sig do
23
+ params(
24
+ id: ::Symbol,
25
+ arguments: ::T::Array[::CSVPlusPlus::Entities::FunctionCall::ArgumentsType],
26
+ infix: ::T::Boolean
27
+ ).void
28
+ end
16
29
  # @param id [::String] The name of the function
17
30
  # @param arguments [Array<Entity>] The arguments to the function
18
31
  # @param infix [T::Boolean] Whether the function is infix
19
32
  def initialize(id, arguments, infix: false)
20
- super(::CSVPlusPlus::Entities::Type::FunctionCall, id:, arguments:)
33
+ super(arguments:)
21
34
 
35
+ @id = ::T.let(identifier(id), ::Symbol)
22
36
  @infix = infix
23
37
  end
24
38
 
25
- sig { override.params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
26
- # @param runtime [Runtime]
39
+ sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
40
+ # @param position [Position]
27
41
  #
28
42
  # @return [::String]
29
- def evaluate(runtime)
30
- evaluated_arguments = evaluate_arguments(runtime)
43
+ def evaluate(position)
44
+ evaluated_arguments = evaluate_arguments(position)
31
45
 
32
46
  if @infix
33
47
  "(#{evaluated_arguments.join(" #{@id} ")})"
@@ -36,14 +50,24 @@ module CSVPlusPlus
36
50
  end
37
51
  end
38
52
 
39
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
40
- # @param other [Entity]
53
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
54
+ # @param other [BasicObject]
41
55
  #
42
- # @return [boolean]
56
+ # @return [Boolean]
43
57
  def ==(other)
44
- return false unless super
58
+ case other
59
+ when self.class
60
+ @id == other.id && @infix == other.infix
61
+ else
62
+ false
63
+ end
64
+ end
65
+
66
+ private
45
67
 
46
- other.is_a?(self.class) && @id == other.id && @infix == other.infix
68
+ sig { params(position: ::CSVPlusPlus::Runtime::Position).returns(::T::Array[::String]) }
69
+ def evaluate_arguments(position)
70
+ @arguments.map { |arg| arg.evaluate(position) }
47
71
  end
48
72
  end
49
73
  end
@@ -0,0 +1,19 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module CSVPlusPlus
5
+ module Entities
6
+ # Can be included on any class that has a comparable id
7
+ module HasIdentifier
8
+ extend ::T::Sig
9
+
10
+ sig { params(symbol: ::Symbol).returns(::Symbol) }
11
+ # Variables and functions are case insensitive. I hate it but it's how excel is
12
+ #
13
+ # @param symbol [Symbol]
14
+ def identifier(symbol)
15
+ symbol.downcase
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,14 +6,16 @@ module CSVPlusPlus
6
6
  # A number value
7
7
  #
8
8
  # @attr_reader value [Numeric] The parsed number value
9
- class Number < Entity
9
+ class Number < ::CSVPlusPlus::Entities::Entity
10
+ extend ::T::Sig
11
+
10
12
  sig { returns(::Numeric) }
11
13
  attr_reader :value
12
14
 
13
15
  sig { params(value: ::T.any(::String, ::Numeric)).void }
14
16
  # @param value [String, Numeric] Either a +String+ that looks like a number, or an already parsed Numeric
15
17
  def initialize(value)
16
- super(::CSVPlusPlus::Entities::Type::Number)
18
+ super()
17
19
 
18
20
  @value =
19
21
  ::T.let(
@@ -26,22 +28,25 @@ module CSVPlusPlus
26
28
  )
27
29
  end
28
30
 
29
- sig { override.params(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
30
- # @param _runtime [Runtime]
31
+ sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
32
+ # @param _position [Position]
31
33
  #
32
34
  # @return [::String]
33
- def evaluate(_runtime)
35
+ def evaluate(_position)
34
36
  @value.to_s
35
37
  end
36
38
 
37
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
38
- # @param other [Entity]
39
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
40
+ # @param other [BasicObject]
39
41
  #
40
42
  # @return [::T::Boolean]
41
43
  def ==(other)
42
- return false unless super
43
-
44
- other.is_a?(self.class) && @value == other.value
44
+ case other
45
+ when self.class
46
+ @value == other.value
47
+ else
48
+ false
49
+ end
45
50
  end
46
51
  end
47
52
  end
@@ -0,0 +1,77 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module CSVPlusPlus
5
+ module Entities
6
+ # A reference to something - this is typically either a cell reference (handled by +A1Reference+) or a reference
7
+ # to a variable.
8
+ #
9
+ # One sticking point with the design of this class is that we don't know if a reference is a variable reference
10
+ # unless we look at currently defined variables and see if there is one by that name. Since all cell references
11
+ # can be a valid variable name, we can't be sure which is which. So we delegate that decision as late as possible
12
+ # - in #evaluate
13
+ #
14
+ # @attr_reader scoped_to_expand [Expand, nil] If set, the expand in which this variable is scoped to. It cannot be
15
+ # resolved outside of the given expand.
16
+ class Reference < ::CSVPlusPlus::Entities::Entity
17
+ extend ::T::Sig
18
+ include ::CSVPlusPlus::Entities::HasIdentifier
19
+
20
+ sig { returns(::T.nilable(::String)) }
21
+ attr_reader :ref
22
+
23
+ # sig { returns(::T.nilable(::CSVPlusPlus::A1Reference)) }
24
+ # attr_reader :a1_ref
25
+
26
+ sig { params(ref: ::T.nilable(::String), a1_ref: ::T.nilable(::CSVPlusPlus::A1Reference)).void }
27
+ # Either +ref+, +cell_index+ or +row_index+ must be specified.
28
+ #
29
+ # @param ref [Integer, nil] An A1-style cell reference (that will be parsed into it's row/cell indexes).
30
+ # @param a1_ref [Integer, nil] An A1-style cell reference (that will be parsed into it's row/cell indexes).
31
+ def initialize(ref: nil, a1_ref: nil)
32
+ super()
33
+
34
+ raise(::ArgumentError, 'Must specify :ref or :a1_ref') unless ref || a1_ref
35
+
36
+ @ref = ref
37
+ @a1_ref = a1_ref
38
+ end
39
+
40
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
41
+ # @param other [BasicObject]
42
+ #
43
+ # @return [boolean]
44
+ def ==(other)
45
+ case other
46
+ when self.class
47
+ a1_ref == other.a1_ref
48
+ else
49
+ false
50
+ end
51
+ end
52
+
53
+ sig { returns(::CSVPlusPlus::A1Reference) }
54
+ # @return [A1Reference]
55
+ def a1_ref
56
+ @a1_ref ||= ::CSVPlusPlus::A1Reference.new(ref: ::T.must(ref))
57
+ end
58
+
59
+ sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
60
+ # Get the A1-style cell reference
61
+ #
62
+ # @param position [Position] The current position
63
+ #
64
+ # @return [::String] An A1-style reference
65
+ def evaluate(position)
66
+ # TODO: ugh make to_a1_ref not return a nil
67
+ ref || a1_ref.to_a1_ref(position) || ''
68
+ end
69
+
70
+ sig { returns(::T.nilable(::Symbol)) }
71
+ # @return [Symbol]
72
+ def id
73
+ ref && identifier(::T.must(ref).to_sym)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,41 +1,54 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative './entity'
5
+
4
6
  module CSVPlusPlus
5
7
  module Entities
6
- # A runtime value. These are values which can be materialized at any point via the +resolve_fn+
7
- # which takes an ExecutionContext as a param
8
- #
9
- # @attr_reader resolve_fn [lambda] A lambda that is called when the runtime value is resolved
10
- class RuntimeValue < Entity
8
+ # A runtime value. These are values which can be materialized at any point via the +resolve_fn+ which
9
+ # will provide a value depending on the +Runtime+'s current state.
10
+ class RuntimeValue < ::CSVPlusPlus::Entities::Entity
11
11
  extend ::T::Sig
12
12
 
13
- sig { returns(::T::Array[::T.untyped]) }
14
- attr_reader :arguments
15
-
16
- sig { returns(::T.proc.params(arg0: ::CSVPlusPlus::Runtime::Runtime).returns(::CSVPlusPlus::Entities::Entity)) }
17
- attr_reader :resolve_fn
13
+ ResolveFn =
14
+ ::T.type_alias do
15
+ ::T.proc.params(
16
+ position: ::CSVPlusPlus::Runtime::Position,
17
+ arguments: ::T::Enumerable[::CSVPlusPlus::Entities::Entity]
18
+ ).returns(::CSVPlusPlus::Entities::Entity)
19
+ end
20
+ public_constant :ResolveFn
18
21
 
19
22
  sig do
20
- params(
21
- resolve_fn: ::T.proc.params(arg0: ::CSVPlusPlus::Runtime::Runtime).returns(::CSVPlusPlus::Entities::Entity),
22
- arguments: ::T::Array[::T.untyped]
23
- ).void
23
+ params(resolve_fn: ::CSVPlusPlus::Entities::RuntimeValue::ResolveFn).void
24
24
  end
25
25
  # @param resolve_fn [lambda] A lambda that is called when the runtime value is resolved
26
- # @param arguments [Any] Arguments to the runtime value call
27
- def initialize(resolve_fn, arguments: [])
28
- super(::CSVPlusPlus::Entities::Type::RuntimeValue)
29
-
30
- @arguments = arguments
26
+ def initialize(resolve_fn)
31
27
  @resolve_fn = resolve_fn
28
+ super()
29
+ end
30
+
31
+ sig do
32
+ params(
33
+ position: ::CSVPlusPlus::Runtime::Position,
34
+ arguments: ::T::Enumerable[::CSVPlusPlus::Entities::Entity]
35
+ ).returns(::CSVPlusPlus::Entities::Entity)
36
+ end
37
+ # Using the +@resolve_fn+, evaluate this runtime value into an +Entity+ that can be later evaluated
38
+ def call(position, arguments)
39
+ @resolve_fn.call(position, arguments)
32
40
  end
33
41
 
34
- sig { override.params(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
35
- # @param _runtime [Runtime]
42
+ sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
43
+ # Given the current runtime, call +@resolve_fn+ to produce a value
44
+ #
45
+ # @param _position [Position]
36
46
  #
37
- # @return [String]
38
- def evaluate(_runtime)
47
+ # @return [Entities::Entity]
48
+ def evaluate(_position)
49
+ # TODO: we can do a check on arguments here and make sure that the RuntimeValue is being called
50
+ # with the number of arguments it requires
51
+ # @resolve_fn.call(position, ::T.must(arguments)).evaluate(position)
39
52
  '(runtime value)'
40
53
  end
41
54
  end
@@ -6,7 +6,7 @@ module CSVPlusPlus
6
6
  # A string value
7
7
  #
8
8
  # @attr_reader value [String]
9
- class String < Entity
9
+ class String < ::CSVPlusPlus::Entities::Entity
10
10
  extend ::T::Sig
11
11
 
12
12
  sig { returns(::String) }
@@ -15,27 +15,30 @@ module CSVPlusPlus
15
15
  sig { params(value: ::String).void }
16
16
  # @param value [String] The string that has been parsed out of the template
17
17
  def initialize(value)
18
- super(::CSVPlusPlus::Entities::Type::String)
18
+ super()
19
19
 
20
20
  @value = ::T.let(value.gsub(/^"|"$/, ''), ::String)
21
21
  end
22
22
 
23
- sig { override.params(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
24
- # @param _runtime [Runtime]
23
+ sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
24
+ # @param _position [Position]
25
25
  #
26
26
  # @return [::String]
27
- def evaluate(_runtime)
27
+ def evaluate(_position)
28
28
  "\"#{@value}\""
29
29
  end
30
30
 
31
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
32
- # @param other [Entity]
31
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
32
+ # @param other [BasicObject]
33
33
  #
34
34
  # @return [T::Boolean]
35
35
  def ==(other)
36
- return false unless super
37
-
38
- other.is_a?(self.class) && @value == other.value
36
+ case other
37
+ when self.class
38
+ @value == other.value
39
+ else
40
+ false
41
+ end
39
42
  end
40
43
  end
41
44
  end
@@ -3,36 +3,20 @@
3
3
 
4
4
  require_relative 'entities/entity'
5
5
  require_relative 'entities/entity_with_arguments'
6
+ require_relative 'entities/has_identifier'
6
7
 
7
8
  require_relative 'entities/boolean'
8
- require_relative 'entities/cell_reference'
9
9
  require_relative 'entities/date'
10
10
  require_relative 'entities/function'
11
11
  require_relative 'entities/function_call'
12
12
  require_relative 'entities/number'
13
+ require_relative 'entities/reference'
13
14
  require_relative 'entities/runtime_value'
14
15
  require_relative 'entities/string'
15
- require_relative 'entities/variable'
16
16
 
17
17
  module CSVPlusPlus
18
18
  # The entities that form abstract syntax trees which make up the language
19
19
  module Entities
20
- extend ::T::Sig
21
-
22
- # A primitive type. These all correspond to an implementation of the same name in the CSVPlusPlus::Entities module.
23
- class Type < ::T::Enum
24
- enums do
25
- Boolean = new
26
- CellReference = new
27
- Date = new
28
- Function = new
29
- FunctionCall = new
30
- Number = new
31
- RuntimeValue = new
32
- String = new
33
- Variable = new
34
- end
35
- end
36
20
  end
37
21
  end
38
22
 
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module CSVPlusPlus
5
+ module Error
6
+ # An error that represents an invalid CLI option or state
7
+ class CLIError < ::CSVPlusPlus::Error::Error
8
+ extend ::T::Sig
9
+
10
+ sig { override.returns(::String) }
11
+ # @return [String]
12
+ def error_message
13
+ message
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module CSVPlusPlus
5
+ module Error
6
+ # An error that represents an invalid state during compilation.
7
+ class CompilerError < ::CSVPlusPlus::Error::Error
8
+ extend ::T::Sig
9
+
10
+ sig { override.returns(::String) }
11
+ # @return [String]
12
+ def error_message
13
+ message
14
+ end
15
+ end
16
+ end
17
+ end
@@ -4,17 +4,30 @@
4
4
  module CSVPlusPlus
5
5
  module Error
6
6
  # An error thrown by our code (generally to be handled at the top level bin/ command)
7
- class Error < StandardError
7
+ class Error < ::StandardError
8
8
  extend ::T::Sig
9
9
  extend ::T::Helpers
10
10
 
11
- sig { returns(::String) }
11
+ abstract!
12
+
13
+ sig { returns(::T.nilable(::StandardError)) }
14
+ attr_reader :wrapped_error
15
+
16
+ sig { params(message: ::String, wrapped_error: ::T.nilable(::StandardError)).void }
17
+ # @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
18
+ # Racc::ParseError that was thrown
19
+ def initialize(message, wrapped_error: nil)
20
+ super(message)
21
+
22
+ @message = message
23
+ @wrapped_error = wrapped_error
24
+ end
25
+
26
+ sig { abstract.returns(::String) }
12
27
  # Return an error message for display to a command-line user.
13
28
  #
14
29
  # @return [::String]
15
- def error_message
16
- message
17
- end
30
+ def error_message; end
18
31
  end
19
32
  end
20
33
  end
@@ -1,36 +1,35 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative './syntax_error'
5
-
6
4
  module CSVPlusPlus
7
5
  module Error
8
6
  # An error that can be thrown when there is an error parsing a modifier
9
7
  #
10
8
  # @attr_reader message [::String] A helpful error message
11
9
  # @attr_reader bad_input [String] The offending input that caused the error to be thrown
12
- class FormulaSyntaxError < ::CSVPlusPlus::Error::SyntaxError
13
- attr_reader :message, :bad_input
10
+ class FormulaSyntaxError < ::CSVPlusPlus::Error::Error
11
+ extend ::T::Sig
12
+ include ::CSVPlusPlus::Error::PositionalError
14
13
 
15
- # You must supply either a +choices+ or +message+
16
- #
14
+ sig { returns(::String) }
15
+ attr_reader :bad_input
16
+
17
+ sig { params(message: ::String, bad_input: ::String, wrapped_error: ::T.nilable(::StandardError)).void }
17
18
  # @param message [String] A relevant message to show
18
19
  # @param bad_input [String] The offending input that caused the error to be thrown
19
- # @param runtime [Runtime] The current runtime
20
20
  # @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
21
21
  # Racc::ParseError that was thrown
22
- def initialize(message, bad_input, runtime, wrapped_error: nil)
22
+ def initialize(message, bad_input:, wrapped_error: nil)
23
+ super(message, wrapped_error:)
23
24
  @bad_input = bad_input
24
- @message = message
25
-
26
- super(runtime, wrapped_error:)
27
25
  end
28
26
 
27
+ sig { override.returns(::String) }
29
28
  # Create a relevant error message given +@bad_input+ and +@message+.
30
29
  #
31
30
  # @return [::String]
32
31
  def error_message
33
- "#{@message}: \"#{@bad_input}\""
32
+ "#{message}: \"#{bad_input}\""
34
33
  end
35
34
  end
36
35
  end