def generate_creators(self, registry, parent, closure, ident_n = 1): r = [] ident = "\t" * ident_n if not self.prototype: for name in self.signals: r.append("%s%s.%s = _globals.core.createSignal('%s').bind(%s)" %(ident, parent, name, name, parent)) for prop in self.properties: for name, default_value in prop.properties: args = [parent, "'%s'" %prop.type, "'%s'" %name] if lang.value_is_trivial(default_value): args.append(default_value) r.append("\tcore.addProperty(%s)" %(", ".join(args))) for name, prop in self.enums.iteritems(): raise Exception('adding enums in runtime is unsupported, consider putting this property (%s) in prototype' %name) for idx, gen in enumerate(self.children): var = "%s$child%d" %(escape(parent), idx) component = registry.find_component(self.package, gen.component.name) r.append("%svar %s = new _globals.%s(%s)" %(ident, var, component, parent)) r.append("%s%s.%s = %s" %(ident, closure, var, var)) code = self.call_create(registry, ident_n, var, gen, closure) r.append(code) for target, value in self.assignments.iteritems(): if target == "id": if "." in value: raise Exception("expected identifier, not expression") r.append("%s%s._setId('%s')" %(ident, parent, value)) elif target.endswith(".id"): raise Exception("setting id of the remote object is prohibited") else: self.check_target_property(registry, target) if isinstance(value, component_generator): if target != "delegate": var = "%s$%s" %(escape(parent), escape(target)) r.append("//creating component %s" %value.name) r.append("%svar %s = new _globals.%s(%s)" %(ident, var, registry.find_component(value.package, value.component.name), parent)) r.append("%s%s.%s = %s" %(ident, closure, var, var)) code = self.call_create(registry, ident_n, var, value, closure) r.append(code) r.append('%s%s.%s = %s' %(ident, parent, target, var)) else: code = "%svar delegate = new _globals.%s(%s, true)\n" %(ident, registry.find_component(value.package, value.component.name), parent) code += "%svar __closure = { delegate: delegate }\n" %(ident) code += self.call_create(registry, ident_n + 1, 'delegate', value, '__closure') + '\n' code += self.call_setup(registry, ident_n + 1, 'delegate', value, '__closure') + '\n' r.append("%s%s.%s = (function() {\n%s\n%sreturn delegate\n}).bind(%s)" %(ident, parent, target, code, ident, parent)) for name, target in self.aliases.iteritems(): get, pname = generate_accessors(target) r.append("%score.addAliasProperty(%s, '%s', (function() { return %s; }).bind(%s), '%s')" \ %(ident, parent, name, get, parent, pname)) return "\n".join(r)
def add_child(self, child): t = type(child) if t is lang.Property: self.properties.append(child) for name, default_value in child.properties: if self.has_property(name): raise Exception("duplicate property " + name) #print self.name, name, default_value, lang.value_is_trivial(default_value) if child.lazy: if not isinstance(default_value, lang.Component): raise Exception( "lazy property must be declared with component as value" ) if len(child.properties) != 1: raise Exception( "property %s is lazy, hence should be declared alone" % name) self.lazy_properties[ name] = self.create_component_generator( default_value, '<lazy:%s>' % name) if child.const: if len(child.properties) != 1: raise Exception( "property %s is const, hence should be declared alone" % name) self.const_properties[name] = default_value #string code self.declared_properties[name] = child if default_value is not None and not child.const: if not child.lazy and not lang.value_is_trivial( default_value): self.assign(name, default_value) elif t is lang.AliasProperty: if self.has_property(child.name): raise Exception("duplicate property " + child.name) self.aliases[child.name] = child.target elif t is lang.EnumProperty: if self.has_property(child.name): raise Exception("duplicate property " + child.name) self.enums[child.name] = child elif t is lang.Assignment: if child.target == 'id': raise Exception('assigning non-id for id') self.assign(child.target, child.value) elif t is lang.IdAssignment: self.id = child.name self.assign("id", child.name) elif t is lang.Component: value = self.create_component_generator(child) self.children.append(value) elif t is lang.Behavior: for target in child.target: if target in self.animations: raise Exception("duplicate animation on property " + target) value = self.create_component_generator( child.animation, "<anonymous-animation>") self.animations[target] = value elif t is lang.Method: for name in child.name: if name == 'constructor': if self.ctor != '': raise Exception("duplicate constructor") self.ctor = "\t//custom constructor:\n\t" + child.code + "\n" elif name == 'prototypeConstructor': if not self.prototype: raise Exception( 'prototypeConstructor can be used only in prototypes' ) if self.prototype_ctor != '': raise Exception("duplicate constructor") self.prototype_ctor = child.code else: fullname, args, code = split_name( name), child.args, child.code if fullname in self.methods: raise Exception("duplicate method " + name) self.methods[ fullname] = args, code, child.event #fixme: fix code duplication here elif t is lang.Signal: name = child.name if name in self.signals: raise Exception("duplicate signal " + name) self.signals.add(name) elif t is lang.ListElement: self.elements.append(child.data) elif t is lang.AssignmentScope: for assign in child.values: self.assign(child.target + '.' + assign.target, assign.value) else: raise Exception("unhandled element: %s" % child)
def generate_creators(self, registry, parent, closure, ident_n=1): r = [] ident = "\t" * ident_n if not self.prototype: for name in self.signals: r.append( "%s%s.%s = _globals.core.createSignal('%s').bind(%s)" % (ident, parent, name, name, parent)) for prop in self.properties: for name, default_value in prop.properties: if prop.lazy: gen = self.lazy_properties[name] r.append( self.generate_lazy_property( registry, parent, prop.type, name, gen, ident_n)) elif prop.const: r.append( self.generate_const_property( registry, parent, name, self.const_properties[name])) else: args = [parent, "'%s'" % prop.type, "'%s'" % name] if lang.value_is_trivial(default_value): default_value, deps = parse_deps( '@error', default_value, partial(self.transform_root, registry)) if deps: raise Exception( 'trivial value emits dependencies') args.append(default_value) r.append("\tcore.addProperty(%s)" % (", ".join(args))) for name, prop in self.enums.iteritems(): raise Exception( 'adding enums in runtime is unsupported, consider putting this property (%s) in prototype' % name) for idx, gen in enumerate(self.children): var = "%s$child%d" % (escape(parent), idx) component = registry.find_component(self.package, gen.component.name) r.append("%svar %s = new _globals.%s(%s)" % (ident, var, component, parent)) r.append("%s%s.%s = %s" % (ident, closure, var, var)) code = self.call_create(registry, ident_n, var, gen, closure) r.append(code) r.append("%s%s.addChild(%s)" % (ident, parent, var)) for target, value in self.assignments.iteritems(): if target == "id": if "." in value: raise Exception("expected identifier, not expression") r.append("%s%s._setId('%s')" % (ident, parent, value)) elif target.endswith(".id"): raise Exception( "setting id of the remote object is prohibited") else: self.check_target_property(registry, target) if isinstance(value, component_generator): if target != "delegate": var = "%s$%s" % (escape(parent), escape(target)) r.append("//creating component %s" % value.name) r.append( "%svar %s = new _globals.%s(%s)" % (ident, var, registry.find_component( value.package, value.component.name), parent)) r.append("%s%s.%s = %s" % (ident, closure, var, var)) code = self.call_create(registry, ident_n, var, value, closure) r.append(code) r.append('%s%s.%s = %s' % (ident, parent, target, var)) else: code = self.generate_creator_function( registry, 'delegate', value, ident_n) r.append("%s%s.%s = %s" % (ident, parent, target, code)) for name, target in self.aliases.iteritems(): get, pname = generate_accessors( parent, target, partial(self.transform_root, registry)) r.append("%score.addAliasProperty(%s, '%s', function() { return %s }, '%s')" \ %(ident, parent, name, get, pname)) return "\n".join(r)
def generate_prototype(self, registry, ident_n=1): assert self.prototype == True r = [] ident = "\t" * ident_n base_type = self.get_base_type(registry) r.append( "%svar %s = %s.prototype = Object.create(%s)\n" % (ident, self.proto_name, self.local_name, self.base_proto_name)) if self.prototype_ctor: r.append("\t%s\n" % (self.prototype_ctor)) r.append("%s%s.constructor = %s\n" % (ident, self.proto_name, self.local_name)) r.append("%s%s.componentName = '%s'" % (ident, self.proto_name, self.name)) for name in self.signals: r.append("%s%s.%s = _globals.core.createSignal('%s')" % (ident, self.proto_name, name, name)) for prop in self.properties: for name, default_value in prop.properties: if prop.lazy: gen = self.lazy_properties[name] r.append( self.generate_lazy_property(registry, self.proto_name, prop.type, name, gen, ident_n)) elif prop.const: r.append( self.generate_const_property( registry, self.proto_name, name, self.const_properties[name])) else: args = [ "%s" % self.proto_name, "'%s'" % prop.type, "'%s'" % name ] if lang.value_is_trivial(default_value): default_value, deps = parse_deps( '@error', default_value, partial(self.transform_root, registry)) if deps: raise Exception('trivial value emits dependencies') args.append(default_value) r.append("%score.addProperty(%s)" % (ident, ", ".join(args))) for name, prop in self.enums.iteritems(): values = prop.values for i in xrange(0, len(values)): r.append("/** @const @type {number} */") r.append("%s%s.%s = %d" % (ident, self.proto_name, values[i], i)) r.append("/** @const @type {number} */") r.append("%s%s.%s = %d" % (ident, self.local_name, values[i], i)) args = [self.proto_name, "'enum'", "'%s'" % name] if prop.default is not None: args.append("%s.%s" % (self.local_name, prop.default)) r.append("%score.addProperty(%s)" % (ident, ", ".join(args))) def next_codevar(lines, code, index): var = "$code$%d" % index code = '%svar %s = %s' % (ident, var, code) lines.append(code) return var def put_in_prototype(handler): path, name = handler return not path and self.prototype code_index = 0 for code, methods in self.transform_handlers(registry, self.methods): if len(methods) > 1: code = next_codevar(r, code, code_index) code_index += 1 for path, name in methods: if path: raise Exception( 'no <id> qualifiers (%s) allowed in prototypes %s (%s)' % (path, name, self.name)) r.append("%s%s.%s = %s" % (ident, self.proto_name, name, code)) for code, handlers in self.transform_handlers(registry, self.changed_handlers): handlers = filter(put_in_prototype, handlers) if not handlers: continue if len(handlers) > 1: code = next_codevar(r, code, code_index) code_index += 1 for (path, name) in handlers: assert not path r.append("%s_globals.core._protoOnChanged(%s, '%s', %s)" % (ident, self.proto_name, name, code)) for code, handlers in self.transform_handlers(registry, self.signal_handlers): handlers = filter( lambda h: put_in_prototype(h) and h[1] != 'completed', handlers) if not handlers: continue if len(handlers) > 1: code = next_codevar(r, code, code_index) code_index += 1 for path, name in handlers: r.append("%s_globals.core._protoOn(%s, '%s', %s)" % (ident, self.proto_name, name, code)) for code, handlers in self.transform_handlers(registry, self.key_handlers): handlers = filter(put_in_prototype, handlers) if not handlers: continue if len(handlers) > 1: code = next_codevar(r, code, code_index) code_index += 1 for (path, name) in handlers: r.append("%s_globals.core._protoOnKey(%s, '%s', %s)" % (ident, self.proto_name, name, code)) generate = False code = self.generate_creators(registry, '$this', '$c', ident_n + 1).strip() if code: generate = True b = '\t%s%s.$c.call(this, $c.$b = { })' % (ident, self.base_proto_name) code = '%s%s.$c = function($c) {\n\t\tvar $this = this;\n%s\n%s\n%s}' \ %(ident, self.proto_name, b, code, ident) setup_code = self.generate_setup_code(registry, '$this', '$c', ident_n + 2).strip() b = '%s%s.$s.call(this, $c.$b); delete $c.$b' % (ident, self.base_proto_name) if setup_code: generate = True setup_code = '%s%s.$s = function($c) {\n\t\tvar $this = this;\n%s\n%s\n}' \ %(ident, self.proto_name, b, setup_code) if generate: r.append('') r.append(code) r.append(setup_code) r.append('') return "\n".join(r)
def add_child(self, child): t = type(child) if t is lang.Property: self.properties.append(child) for name, default_value in child.properties: if self.has_property(name): raise Exception("duplicate property " + name) #print name, default_value, lang.value_is_trivial(default_value) self.declared_properties[name] = child if default_value is not None: if not lang.value_is_trivial(default_value): self.assign(name, default_value) elif t is lang.AliasProperty: if self.has_property(child.name): raise Exception("duplicate property " + child.name) self.aliases[child.name] = child.target elif t is lang.EnumProperty: if self.has_property(child.name): raise Exception("duplicate property " + child.name) self.enums[child.name] = child elif t is lang.Assignment: if child.target == 'id': raise Exception('assigning non-id for id') self.assign(child.target, child.value) elif t is lang.IdAssignment: self.id = child.name self.assign("id", child.name) elif t is lang.Component: self.children.append(component_generator(self.ns, self.package + ".<anonymous>", child)) elif t is lang.Behavior: for target in child.target: if target in self.animations: raise Exception("duplicate animation on property " + target); self.animations[target] = component_generator(self.ns, self.package + ".<anonymous-animation>", child.animation) elif t is lang.Method: fullname, args, code = split_name(child.name), child.args, child.code path, name = fullname if child.event and len(name) > 2 and name != "onChanged" and name.startswith("on") and name[2].isupper(): #onXyzzy name = name[2].lower() + name[3:] fullname = path, name if name.endswith("Pressed"): name = name[0].upper() + name[1:-7] fullname = path, name if fullname in self.key_handlers: raise Exception("duplicate key handler " + child.name) self.key_handlers[fullname] = code elif name.endswith("Changed"): name = name[:-7] fullname = path, name if fullname in self.changed_handlers: raise Exception("duplicate signal handler " + child.name) self.changed_handlers[fullname] = code else: if fullname in self.signal_handlers: raise Exception("duplicate signal handler " + child.name) self.signal_handlers[fullname] = args, code else: if fullname in self.methods: raise Exception("duplicate method " + name) self.methods[fullname] = args, code elif t is lang.Constructor: self.ctor = "\t//custom constructor:\n\t" + child.code + "\n" elif t is lang.Signal: name = child.name if name in self.signals: raise Exception("duplicate signal " + name) self.signals.add(name) elif t is lang.ListElement: self.elements.append(child.data) elif t is lang.AssignmentScope: for assign in child.values: self.assign(child.target + '.' + assign.target, assign.value) else: raise Exception("unhandled element: %s" %child)
def generate_prototype(self, registry, ident_n = 1): assert self.prototype == True #HACK HACK: make immutable registry.id_set = set(['context']) self.collect_id(registry.id_set) r = [] ident = "\t" * ident_n base_type = self.get_base_type(registry) r.append("%svar %s = %s.prototype = Object.create(%s)\n" %(ident, self.proto_name, self.local_name, self.base_proto_name)) r.append("%s%s.constructor = %s\n" %(ident, self.proto_name, self.local_name)) r.append("%s%s.componentName = '%s'" %(ident, self.proto_name, self.name)) for name in self.signals: r.append("%s%s.%s = _globals.core.createSignal('%s')" %(ident, self.proto_name, name, name)) for _name, argscode in self.methods.iteritems(): path, name = _name if path: raise Exception('no <id> qualifiers (%s) allowed in prototypes %s (%s)' %(path, name, self.name)) args, code = argscode code = process(code, self, registry) r.append("%s%s.%s = function(%s) %s" %(ident, self.proto_name, name, ",".join(args), code)) for prop in self.properties: for name, default_value in prop.properties: args = ["%s" %self.proto_name, "'%s'" %prop.type, "'%s'" %name] if lang.value_is_trivial(default_value): args.append(default_value) r.append("%score.addProperty(%s)" %(ident, ", ".join(args))) for name, prop in self.enums.iteritems(): values = prop.values for i in xrange(0, len(values)): r.append("/** @const @type {number} */") r.append("%s%s.%s = %d" %(ident, self.proto_name, values[i], i)) r.append("/** @const @type {number} */") r.append("%s%s.%s = %d" %(ident, self.local_name, values[i], i)) args = [self.proto_name, "'enum'", "'%s'" %name] if prop.default is not None: args.append("%s.%s" %(self.local_name, prop.default)) r.append("%score.addProperty(%s)" %(ident, ", ".join(args))) for _name, code in self.changed_handlers.iteritems(): path, name = _name if path or not self.prototype: #sync with condition below continue assert not path code = process(code, self, registry) r.append("%s_globals.core._protoOnChanged(%s, '%s', (function(value) %s ))" %(ident, self.proto_name, name, code)) for _name, argscode in self.signal_handlers.iteritems(): path, name = _name if path or not self.prototype or name == 'completed': #sync with condition below continue args, code = argscode code = process(code, self, registry) r.append("%s_globals.core._protoOn(%s, '%s', (function(%s) %s ))" %(ident, self.proto_name, name, ", ".join(args), code)) for _name, code in self.key_handlers.iteritems(): path, name = _name if path or not self.prototype: #sync with condition below continue code = process(code, self, registry) r.append("%s_globals.core._protoOnKey(%s, '%s', (function(key, event) %s ))" %(ident, self.proto_name, name, code)) generate = False code = self.generate_creators(registry, 'this', '__closure', ident_n + 1).strip() if code: generate = True b = '\t%s%s.__create.call(this, __closure.__base = { })' %(ident, self.base_proto_name) code = '%s%s.__create = function(__closure) {\n%s\n%s\n%s}' \ %(ident, self.proto_name, b, code, ident) setup_code = self.generate_setup_code(registry, 'this', '__closure', ident_n + 2).strip() b = '%s%s.__setup.call(this, __closure.__base); delete __closure.__base' %(ident, self.base_proto_name) if setup_code: generate = True setup_code = '%s%s.__setup = function(__closure) {\n%s\n%s\n}' \ %(ident, self.proto_name, b, setup_code) if generate: r.append('') r.append(code) r.append(setup_code) r.append('') return "\n".join(r)