<commit_before>_ = require "underscore"
Util = require "../Util/Util"
Dataflow = require "../Dataflow/Dataflow"
Evaluator = require "../Evaluator/Evaluator"
Node = require "./Node"
Link = require "./Link"
Model = require "./Model"


class CircularReferenceError extends Error
  constructor: (@attributePath) ->
    labels = _.pluck(@attributePath, 'label')
    @message = "Circular reference: #{labels.join(' -> ')}"

module.exports = Attribute = Node.createVariant
  constructor: ->
    # Call "super" constructor
    Node.constructor.apply(this, arguments)

    @value = Dataflow.cell(@_value.bind(this))

  _value: ->
    if @circularReferenceError
      return @circularReferenceError

    # Optimization
    if @isNumber()
      return parseFloat(@exprString)

    if @_isDirty()
      @_updateCompiledExpression()

    referenceValues = _.mapObject @references(), (referenceAttribute) ->
      referenceAttribute.value()

    try
      return @__compiledExpression.evaluate(referenceValues)
    catch error
      if error instanceof Dataflow.UnresolvedSpreadError
        throw error
      else
        return error

  _isDirty: ->
    return true if !@hasOwnProperty("__compiledExpression")
    return true if @__compiledExpression.exprString != @exprString
    return false

  _updateCompiledExpression: ->
    compiledExpression = new CompiledExpression(this)
    if compiledExpression.isSyntaxError
      compiledExpression.fn = @__compiledExpression?.fn ? -> new Error("Syntax error")
    @__compiledExpression = compiledExpression

  setExpression: (exprString, references={}) ->
    @exprString = String(exprString)

    # Remove all existing reference links
    for referenceLink in @childrenOfType(Model.ReferenceLink)
      @removeChild(referenceLink)

    # Create appropriate reference links
    for own key, attribute of references
      referenceLink = Model.ReferenceLink.createVariant()
      referenceLink.key = key
      referenceLink.setTarget(attribute)
      @addChild(referenceLink)

  references: ->
    references = {}
    for referenceLink in @childrenOfType(Model.ReferenceLink)
      key = referenceLink.key
      attribute = referenceLink.target()
      references[key] = attribute
    return references

  hasReferences: -> _.any(@references(), -> true)

  isNumber: ->
    return Util.isNumberString(@exprString)

  isTrivial: ->
    # TODO
    return @isNumber()

  isNovel: ->
    @hasOwnProperty("exprString")

  # Returns all referenced attributes recursively. In other words every
  # attribute which, if it changed, would affect me.
  dependencies: ->
    dependencies = []
    attributePath = []
    recurse = (attribute) ->
      # Make sure there aren't any circular references
      if attributePath.indexOf(attribute) != -1
        attributePath.push(attribute)  # for error debugging
        throw new CircularReferenceError(attributePath)
      attributePath.push(attribute)
      for referenceAttribute in _.values(attribute.references())
        dependencies.push(referenceAttribute)
        recurse(referenceAttribute)
      attributePath.pop()

    try
      recurse(this)
    catch error
      if error instanceof CircularReferenceError
        @circularReferenceError = error
        return []
      else
        throw error
    @circularReferenceError = null
    dependencies = _.unique(dependencies)
    return dependencies

  parentElement: ->
    result = @parent()
    until result.isVariantOf(Model.Element)
      result = result.parent()
    return result




class CompiledExpression
  constructor: (@attribute) ->
    @exprString = @attribute.exprString
    @referenceKeys = _.keys(@attribute.references())

    if @exprString == ""
      @_setSyntaxError()
      return

    if Util.isNumberString(@exprString)
      value = parseFloat(@exprString)
      @_setConstant(value)
      return<commit_msg>whoops; don't wanna serialize that<commit_after>_ = require "underscore"
Util = require "../Util/Util"
Dataflow = require "../Dataflow/Dataflow"
Evaluator = require "../Evaluator/Evaluator"
Node = require "./Node"
Link = require "./Link"
Model = require "./Model"


class CircularReferenceError extends Error
  constructor: (@attributePath) ->
    labels = _.pluck(@attributePath, 'label')
    @message = "Circular reference: #{labels.join(' -> ')}"

module.exports = Attribute = Node.createVariant
  constructor: ->
    # Call "super" constructor
    Node.constructor.apply(this, arguments)

    @value = Dataflow.cell(@_value.bind(this))

  _value: ->
    if @__circularReferenceError
      return @__circularReferenceError

    # Optimization
    if @isNumber()
      return parseFloat(@exprString)

    if @_isDirty()
      @_updateCompiledExpression()

    referenceValues = _.mapObject @references(), (referenceAttribute) ->
      referenceAttribute.value()

    try
      return @__compiledExpression.evaluate(referenceValues)
    catch error
      if error instanceof Dataflow.UnresolvedSpreadError
        throw error
      else
        return error

  _isDirty: ->
    return true if !@hasOwnProperty("__compiledExpression")
    return true if @__compiledExpression.exprString != @exprString
    return false

  _updateCompiledExpression: ->
    compiledExpression = new CompiledExpression(this)
    if compiledExpression.isSyntaxError
      compiledExpression.fn = @__compiledExpression?.fn ? -> new Error("Syntax error")
    @__compiledExpression = compiledExpression

  setExpression: (exprString, references={}) ->
    @exprString = String(exprString)

    # Remove all existing reference links
    for referenceLink in @childrenOfType(Model.ReferenceLink)
      @removeChild(referenceLink)

    # Create appropriate reference links
    for own key, attribute of references
      referenceLink = Model.ReferenceLink.createVariant()
      referenceLink.key = key
      referenceLink.setTarget(attribute)
      @addChild(referenceLink)

  references: ->
    references = {}
    for referenceLink in @childrenOfType(Model.ReferenceLink)
      key = referenceLink.key
      attribute = referenceLink.target()
      references[key] = attribute
    return references

  hasReferences: -> _.any(@references(), -> true)

  isNumber: ->
    return Util.isNumberString(@exprString)

  isTrivial: ->
    # TODO
    return @isNumber()

  isNovel: ->
    @hasOwnProperty("exprString")

  # Returns all referenced attributes recursively. In other words every
  # attribute which, if it changed, would affect me.
  dependencies: ->
    dependencies = []
    attributePath = []
    recurse = (attribute) ->
      # Make sure there aren't any circular references
      if attributePath.indexOf(attribute) != -1
        attributePath.push(attribute)  # for error debugging
        throw new CircularReferenceError(attributePath)
      attributePath.push(attribute)
      for referenceAttribute in _.values(attribute.references())
        dependencies.push(referenceAttribute)
        recurse(referenceAttribute)
      attributePath.pop()

    try
      recurse(this)
    catch error
      if error instanceof CircularReferenceError
        @__circularReferenceError = error
        return []
      else
        throw error
    @__circularReferenceError = null
    dependencies = _.unique(dependencies)
    return dependencies

  parentElement: ->
    result = @parent()
    until result.isVariantOf(Model.Element)
      result = result.parent()
    return result




class CompiledExpression
  constructor: (@attribute) ->
    @exprString = @attribute.exprString
    @referenceKeys = _.keys(@attribute.references())

    if @exprString == ""
      @_setSyntaxError()
      return

    if Util.isNumberString(@exprString)
      value = parseFloat(@exprString)
      @_setConstant(value)
      return
{'fraction_non_alphanumeric': 0.09588864544400051, 'fraction_numerical': 0.0002577651759247326, 'mean_word_length': 3.308717379233759, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4523311', 'n_tokens_mistral': 2066, 'n_tokens_neox': 2004, 'n_words': 510}