Permalink
Browse files

Removing old compilation infrastructure.

  • Loading branch information...
1 parent 3f2c348 commit 847157313cb4ea0e1b2b65c34bf4abacfb0a4a58 @molnarg committed Jul 18, 2012
View
@@ -1,5 +1,4 @@
var def = require('def.js')
- , linker = require('./linker')
, _ = require('underscore')
var Schema = module.exports = function() {}
@@ -25,21 +24,11 @@ Schema.prototype = {
throw new Error('There\'s no object that satisfies this schema.')
}
if (leafs.uncertain.indexOf(Schema.self) !== -1) {
- // If the validate function is compiled then recompiling it with self inlining
- if (this.compile) {
- var newValidate = linker.link(this.compile(), Schema.self.validate)
- for (var key in this.validate) newValidate[key] = this.validate[key]
- newValidate.schema = newValidate
- this.validate = newValidate
- }
-
// schema.self needs to be pointed to this schema, and then it must be reset
Schema.self.set(this.validate)
}
}
- delete this.validate.assembly
-
return this.validate
},
@@ -78,15 +67,14 @@ Schema.fromJSON = def()
Schema.extend = function(descriptor) {
- if (!descriptor.compile && !descriptor.validate) {
- throw new Error('Schema objects must have either compile or validate function.')
+ if (!descriptor.validate) {
+ throw new Error('Schema objects must have a validate function.')
}
var constructor = function() {
if (this.initialize) this.initialize.apply(this, arguments)
- this.validate = this.compile ? linker.link(this.compile())
- : this.validate.bind(this)
+ this.validate = this.validate.bind(this)
this.validate.schema = this.validate
}
View
@@ -10,36 +10,25 @@ var ArraySchema = module.exports = Schema.extend({
this.max = max || Infinity
},
- compile : function() {
- var compiled = { }
-
+ validate : function(instance) {
// Instance must be an instance of Array
- compiled.fn = 'if (!(instance instanceof Array)) return false;'
+ if (!(instance instanceof Array)) return false
// Checking length
- if (this.min > 0 || this.max < Infinity) {
- var checks = []
- if (this.min === this.max) {
- checks.push('instance.length !== ' + this.min)
- } else {
- if (this.min > 0 ) checks.push('instance.length < ' + this.min)
- if (this.max < Infinity) checks.push('instance.length > ' + this.max)
- }
- compiled.fn += 'if (' + checks.join(' || ') + ') return false;'
+ if (this.min === this.max) {
+ if (instance.length !== this.min) return false
+
+ } else {
+ if (this.min > 0 && instance.length < this.min) return false
+ if (this.max < Infinity && instance.length > this.max) return false
}
// Checking conformance to the given item schema
- if (this.itemSchema !== anything) {
- compiled.references = [this.itemSchema.validate]
- compiled.fn += 'for (var i = 0; i < instance.length; i++) {'
- + ' if (!{0}(instance[i])) return false;'
- + '}'
+ for (var i = 0; i < instance.length; i++) {
+ if (!this.itemSchema.validate(instance[i])) return false;
}
- // If every check passes, return true
- compiled.fn += 'return true;'
-
- return compiled
+ return true
},
generate : function() {
@@ -1,8 +1,8 @@
var Schema = require('../Schema')
var BooleanSchema = new Schema.extend({
- compile : function() {
- return { expression : 'Object(instance) instanceof Boolean' }
+ validate : function(instance) {
+ return Object(instance) instanceof Boolean
},
generate : function() {
View
@@ -46,23 +46,13 @@ var NumberSchema = module.exports = Schema.extend({
publicFunctions : [ 'min', 'above', 'max', 'below', 'step' ],
- compile : function() {
- var references = [this.minimum, this.maximum, this.divisibleBy]
- , checks = ['Object(instance) instanceof Number']
-
- if (this.minimum !== -Infinity) {
- checks.push('instance ' + (this.exclusiveMinimum ? '>' : '>=') + ' {0}')
- }
-
- if (this.maximum !== Infinity) {
- checks.push('instance ' + (this.exclusiveMaximum ? '<' : '<=') + ' {1}')
- }
-
- if (this.divisibleBy !== 0) {
- checks.push('instance % {2} === 0')
- }
-
- return { references : references, expression : checks.join(' && ') }
+ validate : function(instance) {
+ return (Object(instance) instanceof Number) &&
+ (this.exclusiveMinimum ? instance > this.minimum
+ : instance >= this.minimum) &&
+ (this.exclusiveMaximum ? instance < this.maximum
+ : instance <= this.maximum) &&
+ (this.divisibleBy === 0 || instance % this.divisibleBy === 0)
},
generate : function() {
View
@@ -1,116 +0,0 @@
-var native_functions = [Boolean, Number, String, Object, Array, Function, Date]
-var instance_regexp = RegExp('(\\W|^)instance(\\W|$)', 'g')
-
-var c = 0
-var counter = function() { return c++ }
-
-var replace = function(assembly, regexp, target) {
- var replace = function(str) { return str.replace(regexp, target) }
- assembly.expression = replace(assembly.expression)
- assembly.subroutines = assembly.subroutines.map(replace)
-}
-
-var linker = {
- resolve_references : function(assembly) {
- var id, reference, variable, referenced_assembly, resolved
-
- while (assembly.references.length > 0) {
- reference = assembly.references.pop()
- id = assembly.references.length
-
- if (Object(reference) === reference) {
- if (reference.schema && reference.schema.assembly) {
- // reference is a compiled schema, merging it
- referenced_assembly = reference.schema.assembly
-
- for (var name in referenced_assembly.references) {
- assembly.references[name] = referenced_assembly.references[name]
- }
-
- assembly.subroutines = assembly.subroutines.concat(referenced_assembly.subroutines)
-
- resolved = function(match, validate, call, param) {
- var expr = referenced_assembly.expression.replace(instance_regexp, '$1' + param + '$2')
- return '(' + expr + ')'
- }
-
- } else if (native_functions.indexOf(reference) != -1) {
- // native functions can be referenced by name
- resolved = reference.name + '$1'
-
- } else if (reference instanceof RegExp) {
- // regexps can be converted to strings easily
- resolved = reference.toString() + '$1'
-
- } else {
- // reference is an object, or a not compiled schema, it remains reference
- variable = 'r' + counter()
-
- assembly.references[variable] = reference
-
- resolved = variable + '$1'
- }
-
- } else {
- // reference is a primitive value
- if (typeof reference === 'string') {
- resolved = '"' + reference.replace('"', '\\"') + '"'
- } else {
- resolved = reference
- }
- }
-
- // replace strings similar to "{1}.validate(parameter)", where the validate call is optional
- replace(assembly, RegExp('\\{' + id + '\\}((\\.validate)?\\(([^)]*)\\))?', 'g'), resolved)
- }
- },
-
- // An assembly is a compiled version of a schema.
- // Assembly.schema = schema({
- // references : Array.of(Function),
- // subroutines : Array.of(String),
- // expression : String,
- // '?fn' : String
- // })
- //
- // If self is given, it means that references to that schema can be replaced with inline
- // self references, because the schema is sealed, so its code will not be inlined in other schemas
- link : function(assembly, self) {
- assembly.subroutines = assembly.subroutines || []
- assembly.references = assembly.references || []
-
- var name
- if (assembly.fn) {
- name = 'f' + counter()
- assembly.subroutines.push('function ' + name + '(instance){' + assembly.fn + '}')
- assembly.expression = name + '(instance)'
- delete assembly.fn
- }
-
- this.resolve_references(assembly)
-
- // If there's self given, finding and inlining references.
- if (self) {
- for (var key in assembly.references) {
- if (assembly.references[key] !== self) continue
- delete assembly.references[key]
- replace(assembly, RegExp(key + '\\(', 'g'), 'self(')
- }
- }
-
- var closure_arg_names = Object.keys(assembly.references)
- var closure_args = closure_arg_names.map(function(key){ return assembly.references[key] })
- var closure_body = assembly.subroutines.join('\n') + '\n'
- closure_body += assembly.fn ? 'var self = ' + name + ';\n'
- : 'function self(instance){ return ' + assembly.expression + '; }\n'
- closure_body += 'return self;'
- var closure = Function.apply(null, closure_arg_names.concat(closure_body))
- var validate = closure.apply(null, closure_args)
-
- validate.assembly = assembly
-
- return validate
- }
-}
-
-module.exports = linker
View
@@ -2,8 +2,8 @@ var Schema = require('../Schema')
, nothing = require('./nothing')
var AnythingSchema = Schema.extend({
- compile : function() {
- return { expression : 'instance != null' }
+ validate : function(instance) {
+ return instance != null
},
generate : function() {
View
@@ -5,8 +5,8 @@ var ClassSchema = module.exports = Schema.extend({
this.constructor = constructor
},
- compile : function() {
- return { references : [this.constructor], expression : 'instance instanceof {0}' }
+ validate : function(instance) {
+ return instance instanceof this.constructor
},
generate : function() {
View
@@ -1,8 +1,8 @@
var Schema = require('../Schema')
var NothingSchema = Schema.extend({
- compile : function() {
- return { expression : 'instance == null' }
+ validate : function(instance) {
+ return instance == null
},
generate : function() {
View
@@ -1,6 +1,5 @@
var Schema = require('../Schema')
, RandExp = require('randexp')
- , utils = require('../utils')
, anything = require('./anything')
, nothing = require('./nothing')
, _ = require('underscore')
@@ -23,66 +22,42 @@ var ObjectSchema = module.exports = Schema.extend({
})
},
- compile : function() {
- var checks = ['instance != null']
- , references = []
- , ref = utils.referenceHandler(references)
+ validate : function(instance) {
+ var self = this
+
+ if (instance == null) return false
// Simple string properties
- var check
- for (var key in this.stringProps) {
- check = '{schema}(instance[{key}])'.replace('{schema}', ref(this.stringProps[key].value.validate))
- .replace('{key}', ref(key))
- if (this.stringProps[key].min === 0) {
- check = '(instance[{key}] === undefined || {check})'.replace('{key}', ref(key))
- .replace('{check}', check)
- }
- checks.push(check)
- }
+ var stringPropsValid = Object.keys(this.stringProps).every(function(key) {
+ return (self.stringProps[key].min === 0 && !(key in instance)) ||
+ (self.stringProps[key].value.validate(instance[key]))
+ })
+ if (!stringPropsValid) return false
- if (!this.regexpProps.length && this.other === anything) {
- return { references : references, expression : checks.join(' && ') }
- }
+ // If there are no RegExp and other validator, that's all
+ if (!this.regexpProps.length && this.other === anything) return true
// Regexp and other properties
- var stringPropNames = Object.keys(this.stringProps)
-
- var fn = 'if (!( {checks} )) return false;'.replace('{checks}', checks.join(' && '))
-
- if (this.other !== anything) fn += 'var checked;'
-
- // Iterating over the keys in the instance
- fn += 'for (var key in instance) {'
-
+ var checked
+ for (var key in instance) {
+
// Checking the key against every key regexps
- if (this.other !== anything) fn += 'checked = false;'
- for (var i = 0; i < this.regexpProps.length; i++) {
- if (this.other !== anything) {
- check = '({regexp}.test(key) && (checked = true)) && !{schema}(instance[key])'
- } else {
- check = '{regexp}.test(key) && !{schema}(instance[key])'
- }
- check = 'if (' + check + ') return false;'
- fn += check.replace('{regexp}', ref(this.regexpProps[i].key))
- .replace('{schema}', ref(this.regexpProps[i].value.validate))
- }
+ checked = false
+ var regexpPropsValid = Object.keys(this.regexpProps).every(function(key) {
+ return (!self.regexpProps[key].key.test(key) ||
+ ((checked = true) && self.regexpProps[key].value.validate(instance[key]))
+ )
+ })
+ if (!regexpPropsValid) return false
// If the key is not matched by regexps and by simple string checks
// then check it against this.other
- if (this.other !== anything) {
- check = '!checked && {stringProps}.indexOf(key) === -1 && !{other}(instance[key])'
- check = 'if (' + check + ') return false;'
- fn += check.replace('{stringProps}', ref(stringPropNames))
- .replace('{other}', ref(this.other.validate))
- }
-
- fn += '}'
- // Iteration ends
+ if (!checked && !(key in this.stringProps) && !this.other.validate(instance[key])) return false
+
+ }
// If all checks passed, the instance conforms to the schema
- fn += 'return true;'
-
- return { references : references, fn : fn }
+ return true
},
generate : function() {
Oops, something went wrong.

0 comments on commit 8471573

Please sign in to comment.