<commit_before># expression - cascading symbolic definitions

promise = require 'promise'
events  = require 'events'
path    = require 'path'

class Expression
  # mixin the EventEmitter
  @::[k] = v for k, v of events.EventEmitter.prototype

  constructor: (tag, opts={}) ->
    unless tag? and opts instanceof Object and opts.kind?
      throw @error "must supply 'tag' and 'opts.kind' to create a new Expression"
    tag = undefined unless !!tag
    Object.defineProperties this,
      kind:        value: opts.kind, enumerable: true
      tag:         value: tag, enumerable: true, writable: true
      parent:      value: opts.parent
      scope:       value: opts.scope
      resolve:     value: opts.resolve   ? ->
      predicate:   value: opts.predicate ? -> true
      construct:   value: opts.construct ? (x) -> x
      represent:   value: opts.represent
      expressions: value: []
      _events: writable: true

    @resolve   = @resolve.bind this
    @construct = @construct.bind this
    @predicate = @predicate.bind this

    @[k] = v for own k, v of opts when k not of this

  eval: (data, opts={}) ->
    opts.adaptive ?= true
    data = @construct data
    unless @predicate data
      throw @error "validation error during eval", data
    if opts.adaptive
      @once 'extended', arguments.callee.bind(this, data)
    return data

  propertize: (key, value, property={}) ->
    unless property instanceof Object
      throw @error "unable to propertize with invalid property params"

    property.configurable ?= true
    property.enumerable   ?= value?
    property.name   = key
    property.expr   = this
    property._value = value # private

    # the setter for the property is called with this = property
    property.set = ((val, force=false) -> switch
      when force is true then @_value = val
      else
        val = expr.eval val for expr in @expr.expressions
        unless @expr.predicate val
          throw @expr.error "validation error", val
        if @parent?
          @expr.update @parent, @name, val
        else
          @_value = val
    ).bind property

    # the getter for the property is called with this = property
    property.get = ((xpath) -> switch
      when !!xpath and typeof xpath is 'string'
        xpath = path.normalize xpath
        # check if absolute path? shouldn't support it...
        [ key, rest... ] = (xpath.split('/').filter (x) -> !!x)
        val = if key is '..' then @parent else @_value?[key]
        for key in rest
          break unless val?
          val = if key is '..' then val.__?.parent else val[key]<commit_msg>completed support for XPATH based object traversal, including absolute path<commit_after># expression - cascading symbolic definitions

promise = require 'promise'
events  = require 'events'
path    = require 'path'

class Expression
  # mixin the EventEmitter
  @::[k] = v for k, v of events.EventEmitter.prototype

  constructor: (tag, opts={}) ->
    unless tag? and opts instanceof Object and opts.kind?
      throw @error "must supply 'tag' and 'opts.kind' to create a new Expression"
    tag = undefined unless !!tag
    Object.defineProperties this,
      kind:        value: opts.kind, enumerable: true
      tag:         value: tag, enumerable: true, writable: true
      parent:      value: opts.parent
      scope:       value: opts.scope
      resolve:     value: opts.resolve   ? ->
      predicate:   value: opts.predicate ? -> true
      construct:   value: opts.construct ? (x) -> x
      represent:   value: opts.represent
      expressions: value: []
      _events: writable: true

    @resolve   = @resolve.bind this
    @construct = @construct.bind this
    @predicate = @predicate.bind this

    @[k] = v for own k, v of opts when k not of this

  eval: (data, opts={}) ->
    opts.adaptive ?= true
    data = @construct data
    unless @predicate data
      throw @error "validation error during eval", data
    if opts.adaptive
      @once 'extended', arguments.callee.bind(this, data)
    return data

  propertize: (key, value, property={}) ->
    unless property instanceof Object
      throw @error "unable to propertize with invalid property params"

    property.configurable ?= true
    property.enumerable   ?= value?
    property.name   = key
    property.expr   = this
    property._value = value # private

    # the setter for the property is called with this = property
    property.set = ((val, force=false) -> switch
      when force is true then @_value = val
      else
        val = expr.eval val for expr in @expr.expressions
        unless @expr.predicate val
          throw @expr.error "validation error", val
        if @parent?
          @expr.update @parent, @name, val
        else
          @_value = val
    ).bind property

    # the getter for the property is called with this = property
    property.get = ((xpath) -> switch
      when !!xpath and typeof xpath is 'string'
        xpath = path.normalize xpath
        # establish starting 'val'
        if /^\//.test xpath
          val = @parent
          val = val.__.parent while val?.__?.parent?
        else
          val = @_value
        [ key, rest... ] = (xpath.split('/').filter (x) -> !!x)
        if key?
          val = if key is '..' then @parent else val?[key]
          for key in rest
            break unless val?
            val = if key is '..' then val.__?.parent else val[key]
{'fraction_non_alphanumeric': 0.10216546363131594, 'fraction_numerical': 0.0, 'mean_word_length': 2.3214505224339277, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, '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': '5248171', 'n_tokens_mistral': 1541, 'n_tokens_neox': 1514, 'n_words': 568}