Class: Odin::Transform::TransformParser

Inherits:
Object
  • Object
show all
Defined in:
lib/odin/transform/transform_parser.rb

Defined Under Namespace

Classes: ParseError

Constant Summary collapse

VERB_ARITY =

── Complete Verb Arity Table ──

{
  # Arity 0
  "today" => 0, "now" => 0,

  # Arity 1
  "upper" => 1, "lower" => 1, "trim" => 1, "trimLeft" => 1, "trimRight" => 1,
  "coerceString" => 1, "coerceNumber" => 1, "coerceInteger" => 1,
  "coerceBoolean" => 1, "coerceDate" => 1, "coerceTimestamp" => 1,
  "tryCoerce" => 1, "toArray" => 1, "toObject" => 1,
  "not" => 1, "isNull" => 1, "isString" => 1, "isNumber" => 1,
  "isBoolean" => 1, "isArray" => 1, "isObject" => 1, "isDate" => 1,
  "typeOf" => 1,
  "capitalize" => 1, "titleCase" => 1, "length" => 1, "reverseString" => 1,
  "camelCase" => 1, "snakeCase" => 1, "kebabCase" => 1, "pascalCase" => 1,
  "slugify" => 1, "normalizeSpace" => 1, "stripAccents" => 1, "clean" => 1,
  "wordCount" => 1, "soundex" => 1,
  "abs" => 1, "floor" => 1, "ceil" => 1, "negate" => 1, "sign" => 1,
  "trunc" => 1, "isFinite" => 1, "isNaN" => 1, "ln" => 1, "log10" => 1,
  "exp" => 1, "sqrt" => 1,
  "formatInteger" => 1, "formatCurrency" => 1,
  "startOfDay" => 1, "endOfDay" => 1, "startOfMonth" => 1, "endOfMonth" => 1,
  "startOfYear" => 1, "endOfYear" => 1, "dayOfWeek" => 1, "weekOfYear" => 1,
  "quarter" => 1, "isLeapYear" => 1, "toUnix" => 1, "fromUnix" => 1,
  "dayOfMonth" => 1, "dayOfYear" => 1,
  "base64Encode" => 1, "base64Decode" => 1, "urlEncode" => 1, "urlDecode" => 1,
  "jsonEncode" => 1, "jsonDecode" => 1, "hexEncode" => 1, "hexDecode" => 1,
  "sha256" => 1, "sha1" => 1, "sha512" => 1, "md5" => 1, "crc32" => 1,
  "flatten" => 1, "distinct" => 1, "sort" => 1, "sortDesc" => 1,
  "reverse" => 1, "compact" => 1, "unique" => 1, "cumsum" => 1, "cumprod" => 1,
  "sum" => 1, "count" => 1, "min" => 1, "max" => 1, "avg" => 1,
  "first" => 1, "last" => 1,
  "std" => 1, "stdSample" => 1, "variance" => 1, "varianceSample" => 1,
  "median" => 1, "mode" => 1, "rowNumber" => 1,
  "uuid" => 1, "sequence" => 1, "resetSequence" => 1,
  "keys" => 1, "values" => 1, "entries" => 1,
  "toRadians" => 1, "toDegrees" => 1,
  "nextBusinessDay" => 1, "formatDuration" => 1,

  # Arity 2
  "ifNull" => 2, "ifEmpty" => 2,
  "and" => 2, "or" => 2, "xor" => 2,
  "eq" => 2, "ne" => 2, "lt" => 2, "lte" => 2, "gt" => 2, "gte" => 2,
  "contains" => 2, "startsWith" => 2, "endsWith" => 2,
  "truncate" => 2, "join" => 2,
  "mask" => 2, "match" => 2, "leftOf" => 2, "rightOf" => 2,
  "repeat" => 2, "matches" => 2, "levenshtein" => 2, "tokenize" => 2,
  "add" => 2, "subtract" => 2, "multiply" => 2, "divide" => 2, "mod" => 2,
  "formatNumber" => 2, "pow" => 2, "log" => 2, "formatPercent" => 2,
  "parseInt" => 2, "formatLocaleNumber" => 2, "round" => 2,
  "formatDate" => 2, "parseDate" => 2,
  "addDays" => 2, "addMonths" => 2, "addYears" => 2,
  "addHours" => 2, "addMinutes" => 2, "addSeconds" => 2,
  "formatTime" => 2, "formatTimestamp" => 2, "parseTimestamp" => 2,
  "isBefore" => 2, "isAfter" => 2,
  "daysBetweenDates" => 2, "ageFromDate" => 2, "isValidDate" => 2,
  "formatLocaleDate" => 2,
  "accumulate" => 2, "set" => 2,
  "percentile" => 2, "quantile" => 2, "covariance" => 2, "correlation" => 2,
  "weightedAvg" => 2, "npv" => 2, "irr" => 2, "zscore" => 2,
  "sortBy" => 2, "map" => 2, "indexOf" => 2, "at" => 2,
  "includes" => 2, "concatArrays" => 2, "zip" => 2, "groupBy" => 2,
  "take" => 2, "drop" => 2, "chunk" => 2, "pluck" => 2,
  "dedupe" => 2, "diff" => 2, "pctChange" => 2, "limit" => 2,
  "nanoid" => 2,
  "has" => 2, "merge" => 2, "jsonPath" => 2,
  "assert" => 2,
  "formatPhone" => 2, "movingAvg" => 2, "businessDays" => 2,

  # Arity 3
  "ifElse" => 3, "between" => 3,
  "substring" => 3, "replace" => 3, "replaceRegex" => 3,
  "padLeft" => 3, "padRight" => 3, "pad" => 3,
  "split" => 3, "extract" => 3, "wrap" => 3, "center" => 3,
  "clamp" => 3, "random" => 3, "safeDivide" => 3,
  "dateDiff" => 3, "isBetween" => 3,
  "compound" => 3, "discount" => 3, "pmt" => 3, "fv" => 3, "pv" => 3,
  "depreciation" => 3,
  "slice" => 3, "range" => 3, "shift" => 3, "rank" => 3,
  "lag" => 3, "lead" => 3, "sample" => 3, "fillMissing" => 3,
  "get" => 3,
  "reduce" => 3, "pivot" => 3, "unpivot" => 3, "convertUnit" => 3,

  # Arity 4
  "rate" => 4, "nper" => 4,
  "filter" => 4, "every" => 4, "some" => 4, "find" => 4,
  "findIndex" => 4, "partition" => 4,
  "bearing" => 4, "midpoint" => 4,

  # Arity 5
  "distance" => 5, "interpolate" => 5,

  # Arity 6
  "inBoundingBox" => 6
}.freeze
VARIADIC_VERBS =
%w[
  concat coalesce cond switch lookup lookupDefault minOf maxOf
].freeze
ALL_DIRECTIVES =
%w[
  pos len field trim type date time timestamp boolean integer number
  currency percent binary duration reference leftPad rightPad truncate
  upper lower default decimals currencyCode required confidential
  deprecated attr ns if unless omitNull omitEmpty
].freeze

Instance Method Summary collapse

Instance Method Details

#parse(text) ⇒ Object

Raises:



123
124
125
126
127
128
129
# File 'lib/odin/transform/transform_parser.rb', line 123

def parse(text)
  raise ParseError.new("Transform text cannot be nil", code: "T001") if text.nil?
  raise ParseError.new("Transform text cannot be empty", code: "T001") if text.strip.empty?

  lines = text.lines.map(&:chomp)
  parse_lines(lines)
end

#parse_expression_string(raw) ⇒ Object

Public for testing expression parsing



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/odin/transform/transform_parser.rb', line 132

def parse_expression_string(raw)
  return [LiteralExpr.new(Types::DynValue.of_null), []] if raw.nil? || raw.strip.empty?

  raw = raw.strip
  tokens = tokenize_expression(raw)
  return [LiteralExpr.new(Types::DynValue.of_null), []] if tokens.empty?

  expr, remaining = parse_expr_from_tokens(tokens)
  directives = parse_directives(remaining)
  [expr, directives]
end